blob: 4f5aa7f1678b04f408906b38e5a22e8511454288 [file] [edit]
<!DOCTYPE html>
<!--
Copyright 2016 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/tracing/value/histogram.html">
<link rel="import" href="/tracing/value/legacy_unit_info.html">
<script>
'use strict';
tr.exportTo('tr.v', function() {
class ChartJsonConverter {
/**
* Parses Values from |charts|, converts them to Histograms, and adds those
* to |histograms|.
*
* @param {!Array.<!Object>} charts
* @param {!tr.v.HistogramSet} histograms
*/
static convertChartJson(charts, histograms) {
const traceValues = charts.charts.trace;
// The chromeperf dashboard requires some Diagnostics to be shared, even
// if there is only a single Histogram in the HistogramSet.
const diagnosticCaches = new Map();
function addSharedDiagnostic(hist, name, diagnostic) {
if (!diagnosticCaches.has(name)) {
diagnosticCaches.set(name, new Map());
}
const cache = diagnosticCaches.get(name);
const cacheKey = diagnostic instanceof tr.v.d.GenericSet ?
[...diagnostic].sort().join(',') : diagnostic.minDate;
if (!cache.has(cacheKey)) {
cache.set(cacheKey, diagnostic);
histograms.addSharedDiagnostic(diagnostic);
}
hist.diagnostics.set(name, cache.get(cacheKey));
}
for (const [name, pageValues] of Object.entries(charts.charts)) {
if (name === 'trace') continue;
const pageValuesCount = Object.keys(pageValues).length;
for (const [storyName, value] of Object.entries(pageValues)) {
if (pageValuesCount > 1 && storyName === 'summary') continue;
const unitInfo = tr.v.LEGACY_UNIT_INFO.get(value.units) || {};
const unitName = unitInfo.name || 'unitlessNumber';
const conversionFactor = unitInfo.conversionFactor || 1;
let improvementDirection = tr.b.ImprovementDirection.DONT_CARE;
if (unitInfo.defaultImprovementDirection !== undefined) {
improvementDirection = unitInfo.defaultImprovementDirection;
}
// Metrics have the final say.
if (value.improvement_direction !== undefined) {
improvementDirection =
ChartJsonConverter.convertImprovementDirection(
value.improvement_direction);
}
const unitNameSuffix = tr.b.Unit.nameSuffixForImprovementDirection(
improvementDirection);
const hist = histograms.createHistogram(
value.name || name,
tr.b.Unit.byName[unitName + unitNameSuffix], [], {
binBoundaries: tr.v.HistogramBinBoundaries.SINGULAR,
description: value.description || '',
});
if (traceValues) {
const traceValue = traceValues[storyName] || {};
let traceUrl = traceValue.cloud_url;
if (!traceUrl && traceValue.file_path) {
traceUrl = 'file://' + traceValue.file_path;
}
if (traceUrl) {
addSharedDiagnostic(hist, tr.v.d.RESERVED_NAMES.TRACE_URLS,
new tr.v.d.GenericSet([traceUrl]));
}
}
if (pageValuesCount > 1) {
addSharedDiagnostic(hist, tr.v.d.RESERVED_NAMES.STORIES,
new tr.v.d.GenericSet([storyName]));
}
const storyTags = [];
if (value.grouping_label) {
storyTags.push(`grouping_label:${value.grouping_label}`);
}
if (value.story_tags) {
storyTags.push(...value.story_tags);
}
if (storyTags.length) {
addSharedDiagnostic(hist, tr.v.d.RESERVED_NAMES.STORY_TAGS,
new tr.v.d.GenericSet(storyTags));
}
if (charts.benchmark_name) {
addSharedDiagnostic(hist, tr.v.d.RESERVED_NAMES.BENCHMARKS,
new tr.v.d.GenericSet([charts.benchmark_name]));
}
if (charts.label) {
addSharedDiagnostic(hist, tr.v.d.RESERVED_NAMES.LABELS,
new tr.v.d.GenericSet([charts.label]));
}
if (charts.benchmarkStartMs) {
addSharedDiagnostic(hist, tr.v.d.RESERVED_NAMES.BENCHMARK_START,
new tr.v.d.DateRange(charts.benchmarkStartMs));
}
if (value.type === 'histogram' || value.buckets) {
for (const bucket of value.buckets) {
// Take the center of the bin. This coarse granularity can amplify
// noise when a measurement moves from one bin to the next.
const sample = conversionFactor * (bucket.high + bucket.low) / 2;
for (let i = 0; i < bucket.count; ++i) {
hist.addSample(sample);
}
}
} else if (value.type === 'list_of_scalar_values' || value.values) {
// |value.values| is undefined if the list_of_scalar_values is
// empty.
if (value.values) {
for (const sample of value.values) {
hist.addSample(sample * conversionFactor);
}
}
} else if (value.type === 'scalar' || value.value !== undefined) {
hist.addSample(value.value * conversionFactor);
}
}
}
}
static convertImprovementDirection(improvementDirection) {
switch (improvementDirection) {
case 'down': return tr.b.ImprovementDirection.SMALLER_IS_BETTER;
case 'up': return tr.b.ImprovementDirection.BIGGER_IS_BETTER;
default: return tr.b.ImprovementDirection.DONT_CARE;
}
}
}
return {
ChartJsonConverter,
};
});
</script>