blob: 78f7c6c7c2927c19466db9aef14e3da4e748fc1b [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright 2020 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/metrics/metric_registry.html">
<script>
'use strict';
/**
* This metric is used for custom performance benchmark.
* It captures the following:
* - Recorded trace events with name starts with "custom_metric:" on the C++
* side.
* - Duration between performance.mark('<YOUR_METRIC_NAME>:benchmark_begin')
* and performance.mark('<YOUR_METRIC_NAME>:benchmark_end') on the JS side.
* - performance.mark('<YOUR_METRIC_NAME>:<YOUR_METRIC_VALUE>:benchmark_value')
* on the JS side.
*/
tr.exportTo('tr.metrics', function() {
function customMetric(histograms, model, opt_options) {
const chromeHelper = model.getOrCreateHelper(
tr.model.helpers.ChromeModelHelper);
if (!chromeHelper) {
// Chrome isn't present.
return;
}
const TITLE_PREFIX = 'custom_metric:';
const traces = new Map();
const benchmarkValues = new Map();
// Collect trace events.
for (const helper of chromeHelper.browserHelpers) {
if (!helper.mainThread) continue;
for (const slice of helper.mainThread.sliceGroup.slices.concat(
helper.mainThread.asyncSliceGroup.slices)) {
if (!slice.error && slice.title.startsWith(TITLE_PREFIX)) {
if (!traces.has(slice.title)) {
traces.set(slice.title, []);
}
traces.get(slice.title).push(slice.duration);
}
}
}
// Collect performance.mark().
const BENCHMARK_BEGIN = 'benchmark_begin';
const BENCHMARK_END = 'benchmark_end';
const BENCHMARK_VALUE = 'benchmark_value';
const marks = new Map();
for (const helper of Object.values(chromeHelper.rendererHelpers)) {
for (const event of helper.mainThread.sliceGroup.childEvents()) {
const navId = getNavigationId(event);
if (!navId || !event.category.includes('blink.user_timing')) continue;
const {title} = event;
const index = title.lastIndexOf(':');
if (index === -1) {
continue;
}
const name = title.substring(0, index);
const lastPart = title.substring(index + 1);
if (lastPart === BENCHMARK_BEGIN) {
marks.set(name, event);
} else if (lastPart === BENCHMARK_END) {
if (!marks.has(name)) {
continue;
}
const range = tr.b.math.Range.fromExplicitRange(
marks.get(name).start, event.start);
if (!traces.has(name)) {
traces.set(name, []);
}
traces.get(name).push(range.duration);
marks.delete(name);
} else if (lastPart === BENCHMARK_VALUE) {
const index2 = name.lastIndexOf(':');
if (index2 === -1) {
continue;
}
const key = name.substring(0, index2);
const value = Number(name.substring(index2 + 1));
if (key && !isNaN(value)) {
if (!benchmarkValues.has(key)) {
benchmarkValues.set(key, []);
}
benchmarkValues.get(key).push(value);
}
}
}
}
// Generate histograms.
traces.forEach((value, key) => {
histograms.createHistogram(key,
tr.b.Unit.byName.timeDurationInMs_smallerIsBetter,
value);
});
benchmarkValues.forEach((value, key) => {
histograms.createHistogram(key,
tr.b.Unit.byName.unitlessNumber_smallerIsBetter,
value);
});
}
function getNavigationId(event) {
return event.args.data && event.args.data.navigationId;
}
tr.metrics.MetricRegistry.register(customMetric, {
supportsRangeOfInterest: false,
});
return {
customMetric,
};
});
</script>