| Index: tracing/tracing/metrics/system_health/cpu_time_metric_test.html
|
| diff --git a/tracing/tracing/metrics/system_health/cpu_time_metric_test.html b/tracing/tracing/metrics/system_health/cpu_time_metric_test.html
|
| index 3405d82e1f9e13c742e1bd324bcfcf11bfd498be..f13644c63458b135b5c0b17515945ef71b5c6907 100644
|
| --- a/tracing/tracing/metrics/system_health/cpu_time_metric_test.html
|
| +++ b/tracing/tracing/metrics/system_health/cpu_time_metric_test.html
|
| @@ -7,6 +7,7 @@ found in the LICENSE file.
|
|
|
| <link rel="import" href="/tracing/core/test_utils.html">
|
| <link rel="import" href="/tracing/extras/chrome/chrome_test_utils.html">
|
| +<link rel="import" href="/tracing/extras/chrome/cpu_time_test_utils.html">
|
| <link rel="import" href="/tracing/metrics/system_health/cpu_time_metric.html">
|
| <link rel="import" href="/tracing/value/histogram_set.html">
|
|
|
| @@ -14,146 +15,643 @@ found in the LICENSE file.
|
| 'use strict';
|
|
|
| tr.b.unittest.testSuite(function() {
|
| - function computeCpuTime(customizeModelCallback, opt_options) {
|
| - const model = tr.c.TestUtils.newModel(function(model) {
|
| - customizeModelCallback(model);
|
| - });
|
| + const getThreadType = tr.metrics.sh.getThreadType;
|
| + const calculateCpuTimeFragment = tr.metrics.sh.calculateCpuTimeFragment;
|
| +
|
| + const CHROME_PROCESS_NAMES =
|
| + tr.e.chrome.chrome_processes.CHROME_PROCESS_NAMES;
|
| +
|
| + const buildModelFromSpec = tr.e.chrome.cpuTimeTestUtils.buildModelFromSpec;
|
| + const getSimpleModelSpec = tr.e.chrome.cpuTimeTestUtils.getSimpleModelSpec;
|
| +
|
| + // A very small epsilon to assert with acceptable precision the correctness of
|
| + // small floating point values produced by cpu time metric.
|
| + const EPSILON7 = 1e-7;
|
| +
|
| + // Shorthand for initiator types
|
| + const IT = tr.model.um.INITIATOR_TYPE;
|
| +
|
| + function computeMetricValue(modelSpec, metricName, opt_rangeOfInterest) {
|
| + const model = buildModelFromSpec(modelSpec);
|
| const histograms = new tr.v.HistogramSet();
|
| - tr.metrics.sh.cpuTimeMetric(histograms, model, opt_options);
|
| - return tr.b.getOnlyElement(histograms).average;
|
| + const options = opt_rangeOfInterest ?
|
| + {rangeOfInterest: opt_rangeOfInterest} : undefined;
|
| + tr.metrics.sh.cpuTimeMetric(histograms, model, options);
|
| + return histograms.getHistogramNamed(metricName).sum;
|
| }
|
|
|
| - // There are two slices, each of length 50. The total bounds is 3000.
|
| - // This yields total CPU time of 100ms, averaged over 3 seconds is 33ms.
|
| - test('cpuTimeMetric_oneProcess', function() {
|
| - const sliceDuration = 50;
|
| - const totalDuration = 3000;
|
| - const value = computeCpuTime(function(model) {
|
| - model.rendererProcess = model.getOrCreateProcess(2);
|
| - model.rendererMain = model.rendererProcess.getOrCreateThread(3);
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: 0,
|
| - duration: sliceDuration,
|
| - cpuStart: 0,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: totalDuration - sliceDuration,
|
| - duration: sliceDuration,
|
| - cpuStart: totalDuration - sliceDuration,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - });
|
| - assert.closeTo(value, 0.033, 0.001);
|
| + function assertMetricValueInHistogram(histograms, metricName, expectedValue) {
|
| + const value = histograms.getHistogramNamed(metricName).sum;
|
| + assert.closeTo(value, expectedValue, EPSILON7);
|
| + }
|
| +
|
| + // TODO: DO NOT COMMIT THIS. Fix all instances. This is a temporary
|
| + // workaround while I get the higher level structure of the code sorted out.
|
| + function fixMetricName(name) {
|
| + const parts = name.split(':');
|
| + if (parts[1] === 'GPU') parts[1] = 'gpu_process';
|
| + parts[1] = tr.e.chrome.chrome_processes.canonicalizeProcessName(parts[1]);
|
| + parts[0] = "cpuUsage";
|
| + return parts.join(":");
|
| + }
|
| +
|
| + test('slicesDoNotStraddleExpecationBoundaries', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [100, 300]}
|
| + )
|
| + const metricName = `cpuUsage:${CHROME_PROCESS_NAMES.BROWSER}:` +
|
| + `CrBrowserMain:Animation:CSS`;
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, (30 + 20) / 200, EPSILON7);
|
| + });
|
| +
|
| + test('slicesStraddleExpectationBoundaries', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [75, 175]}
|
| + )
|
| + const metricName = `cpuUsage:${CHROME_PROCESS_NAMES.BROWSER}:` +
|
| + `CrBrowserMain:Animation:Video`;
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, 15 / 100, EPSILON7);
|
| + });
|
| +
|
| + test('singleThread-disjointExpectationsOfSameInitiator', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [100, 160]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [205, 225]}
|
| + )
|
| + const metricName = `cpuUsage:${CHROME_PROCESS_NAMES.BROWSER}` +
|
| + `:CrBrowserMain:Response:Scroll`;
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, (0.2 * 30 + 0.4 * 20) / (60 + 20), EPSILON7);
|
| + });
|
| +
|
| + test('singleThread-overlappingExpectationsOfSameInitiator', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [100, 190]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [170, 230]}
|
| + )
|
| + const metricName = fixMetricName('cpuTime:Browser:CrBrowserMain:Response:Scroll');
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, (30 + .5 * 20) / 130, EPSILON7);
|
| + });
|
| +
|
| + test('singleThread-disjointExpectationsOfDifferentInitiators', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [100, 160]},
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [205, 230]}
|
| + );
|
| + const metricName = fixMetricName('cpuTime:Browser:CrBrowserMain:Animation:all_initiators');
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, (0.2 * 30 + 0.5 * 20) / 85, EPSILON7);
|
| + });
|
| +
|
| + test('singleThread-overlappingExpectationsOfDifferentInitiators', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [100, 190]},
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [160, 230]}
|
| + );
|
| + const metricName = fixMetricName('cpuTime:Browser:CrBrowserMain:Animation:all_initiators');
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, (30 + 0.5 * 20) / 130, EPSILON7);
|
| });
|
|
|
| - // Normalize against the browser process, whose non-CPU slice goes from 2900
|
| - // to 3000.
|
| - test('cpuTimeMetric_browserProcess', function() {
|
| - const sliceDuration = 50;
|
| - const totalDuration = 3000;
|
| - const model = tr.e.chrome.ChromeTestUtils.newChromeModel(function(model) {
|
| - model.browserMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: totalDuration - 2 * sliceDuration,
|
| - duration: 2 * sliceDuration,
|
| - }));
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: 0,
|
| - duration: sliceDuration,
|
| - cpuStart: 0,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: totalDuration - sliceDuration,
|
| - duration: sliceDuration,
|
| - cpuStart: totalDuration - sliceDuration,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - });
|
| + test('singleThread-allStages-customRangeOfInterest', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [100, 190]},
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [160, 230]}
|
| + );
|
| + const metricName = fixMetricName('cpuTime:Browser:CrBrowserMain:all_stages:all_initiators');
|
| + const rangeOfInterest = new tr.b.math.Range.fromExplicitRange(100, 210);
|
| + const value = computeMetricValue(
|
| + simpleModelSpec, metricName, rangeOfInterest);
|
| + assert.closeTo(value, (30 + 0.1 * 20)/ 110, EPSILON7);
|
| + });
|
| +
|
| + test('singleThread-allStages-defaultRangeOfInterest', () => {
|
| + const simpleModelSpec = getSimpleModelSpec();
|
| + simpleModelSpec.processes[0].threads[0].slices.push(
|
| + {range: [150, 200], cpu: 30},
|
| + {range: [205, 255], cpu: 20}
|
| + )
|
| + simpleModelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [160, 230]}
|
| + );
|
| + const metricName = fixMetricName('cpuTime:Browser:CrBrowserMain:all_stages:all_initiators');
|
| + const value = computeMetricValue(simpleModelSpec, metricName);
|
| + assert.closeTo(value, 50 / 105, EPSILON7);
|
| + });
|
| +
|
| + test('multipleThreadsOfSameTypeAggregate', () => {
|
| + const modelSpec = {
|
| + processes: [
|
| + {
|
| + name: 'Browser',
|
| + pid: 12345,
|
| + threads: [
|
| + {
|
| + name: 'CrBrowserMain',
|
| + tid: 1,
|
| + slices: [],
|
| + },
|
| + {
|
| + name: 'Worker/1',
|
| + tid: 42,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 20) {
|
| + slices.push({range:[i, i + 10], cpu: 5});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + {
|
| + name: 'Worker/2',
|
| + tid: 52,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 100) {
|
| + slices.push({range:[i, i + 80], cpu: 40});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ],
|
| + },
|
| + ],
|
| +
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + expectations: [
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [0, 90]},
|
| +
|
| + {stage: 'Response', initiatorType: IT.CLICK, range: [200, 220]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [210, 260]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [250, 300]},
|
| +
|
| +
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [690, 890]},
|
| + ],
|
| + };
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| const histograms = new tr.v.HistogramSet();
|
| tr.metrics.sh.cpuTimeMetric(histograms, model);
|
| - const value = tr.b.getOnlyElement(histograms).average;
|
| - assert.closeTo(value, 0.5, 0.001);
|
| +
|
| + // Single expectation range of same initiator type.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Browser:Worker:Animation:Video'),
|
| + (5 * 5 + 40) / 90);
|
| +
|
| + // Disjoint expectation ranges of same initiator type.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Browser:Worker:Animation:CSS'),
|
| + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)) / (60 + 200));
|
| +
|
| + // Overlapping expectation ranges of same initiator type.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Browser:Worker:Response:Scroll'),
|
| + (5 * 4 + 40 * (70 / 80))/ 90);
|
| +
|
| + // Disjoint expectation ranges with all_initiators.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Browser:Worker:Animation:all_initiators'),
|
| + ((5 * 5 + 40)
|
| + + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)))
|
| + / (90 + 60 + 200));
|
| +
|
| + // Overlapping expectation ranges with all_initiators.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Browser:Worker:Response:all_initiators'),
|
| + (5 * 5 + 40) / 100);
|
| +
|
| + // all_stages and all_initiators.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Browser:Worker:all_stages:all_initiators'),
|
| + (250 + 400) / 990);
|
| });
|
|
|
| - // Makes sure that rangeOfInterest works correctly.
|
| - test('cpuTimeMetric_oneProcess_rangeOfInterest', function() {
|
| - const sliceDuration = 50;
|
| - const totalDuration = 3000;
|
| - const rangeOfInterest = new tr.b.math.Range.fromExplicitRange(-10, 30);
|
| - const options = {};
|
| - options.rangeOfInterest = rangeOfInterest;
|
| - const value = computeCpuTime(function(model) {
|
| - model.rendererProcess = model.getOrCreateProcess(2);
|
| - model.rendererMain = model.rendererProcess.getOrCreateThread(3);
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: 0,
|
| - duration: sliceDuration,
|
| - cpuStart: 0,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: totalDuration - sliceDuration,
|
| - duration: sliceDuration,
|
| - cpuStart: totalDuration - sliceDuration,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - }, options);
|
| - assert.closeTo(value, 0.75, 0.001);
|
| + test('multipleProcessesOfSameTypeAggregate', () => {
|
| + const modelSpec = {
|
| + processes: [
|
| + {
|
| + name: 'Browser',
|
| + pid: 12345,
|
| + threads: [
|
| + {
|
| + name: 'CrBrowserMain',
|
| + tid: 1,
|
| + slices: [],
|
| + },
|
| + ],
|
| + },
|
| + {
|
| + name: 'Renderer',
|
| + pid: 20001,
|
| + threads: [
|
| + {
|
| + name: 'CrRendererMain',
|
| + tid: 42,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 20) {
|
| + slices.push({range:[i, i + 10], cpu: 5});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ],
|
| + },
|
| + {
|
| + name: 'Renderer',
|
| + pid: 30001,
|
| + threads: [
|
| + {
|
| + name: 'CrRendererMain',
|
| + tid: 52,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 100) {
|
| + slices.push({range:[i, i + 80], cpu: 40});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ]
|
| + },
|
| + ],
|
| +
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + expectations: [
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [0, 90]},
|
| +
|
| + {stage: 'Response', initiatorType: IT.CLICK, range: [200, 220]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [210, 260]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [250, 300]},
|
| +
|
| +
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [690, 890]},
|
| + ],
|
| + };
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const histograms = new tr.v.HistogramSet();
|
| + tr.metrics.sh.cpuTimeMetric(histograms, model);
|
| +
|
| + // Single expectation range of same initiator type.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Renderer:CrRendererMain:Animation:Video'),
|
| + (5 * 5 + 40) / 90);
|
| +
|
| + // Disjoint expectation ranges of same initiator type.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Renderer:CrRendererMain:Animation:CSS'),
|
| + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)) / (60 + 200));
|
| +
|
| + // Overlapping expectation ranges of same initiator type.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Renderer:CrRendererMain:Response:Scroll'),
|
| + (5 * 4 + 40 * (70 / 80))/ 90);
|
| +
|
| + // Disjoint expectation ranges with all_initiators.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Renderer:CrRendererMain:Animation:all_initiators'),
|
| + ((5 * 5 + 40)
|
| + + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)))
|
| + / (90 + 60 + 200));
|
| +
|
| + // Overlapping expectation ranges with all_initiators.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Renderer:CrRendererMain:Response:all_initiators'),
|
| + (5 * 5 + 40) / 100);
|
| +
|
| + // all_stages and all_initiators.
|
| + assertMetricValueInHistogram(histograms,
|
| + fixMetricName('cpuTime:Renderer:CrRendererMain:all_stages:all_initiators'),
|
| + (250 + 400) / 990);
|
| + });
|
| +
|
| + test('allThreadsOfSameProcessAggregate', () => {
|
| + const modelSpec = {
|
| + processes: [
|
| + {
|
| + name: 'Browser',
|
| + pid: 12345,
|
| + threads: [
|
| + {
|
| + name: 'CrBrowserMain',
|
| + tid: 1,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 20) {
|
| + slices.push({range:[i, i + 10], cpu: 5});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + {
|
| + name: 'Chrome_IOThread',
|
| + tid: 5,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 100) {
|
| + slices.push({range:[i, i + 80], cpu: 40});
|
| + }
|
| + return slices;
|
| + })(),
|
| + }
|
| + ],
|
| + },
|
| + ],
|
| +
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + expectations: [
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [0, 90]},
|
| +
|
| + {stage: 'Response', initiatorType: IT.CLICK, range: [200, 220]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [210, 260]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [250, 300]},
|
| +
|
| +
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [690, 890]},
|
| + ],
|
| + };
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const histograms = new tr.v.HistogramSet();
|
| + tr.metrics.sh.cpuTimeMetric(histograms, model);
|
| +
|
| + const subMetricPrefix1 =
|
| + 'cpuTime:Browser:CrBrowserMain';
|
| + const subMetricPrefix2 =
|
| + 'cpuTime:Browser:Chrome_IOThread';
|
| + const aggregateMetricPrefix =
|
| + 'cpuTime:Browser:all_threads';
|
| +
|
| + function getMetricValueFromHistogram(histograms, metricName) {
|
| + return histograms.getHistogramNamed(fixMetricName(metricName)).sum;
|
| + }
|
| +
|
| + const metricSuffixes = [
|
| + // Single expectation range of same initiator type.
|
| + 'Animation:Video',
|
| + // Disjoint expectation ranges of same initiator type.
|
| + 'Animation:CSS',
|
| + // Overlapping expectation ranges of same initiator type.
|
| + 'Response:Scroll',
|
| + // Disjoint expectation ranges with all_initiators.
|
| + 'Animation:all_initiators',
|
| + // Overlapping expectation ranges with all_initiators.
|
| + 'Response:all_initiators',
|
| + // all_stages and all_initiators.
|
| + 'all_stages:all_initiators',
|
| + ]
|
| +
|
| + for (const suffix of metricSuffixes) {
|
| + const subMetric1 = getMetricValueFromHistogram(histograms,
|
| + `${subMetricPrefix1}:${suffix}`);
|
| + const subMetric2 = getMetricValueFromHistogram(histograms,
|
| + `${subMetricPrefix2}:${suffix}`);
|
| + const aggregateMetric = getMetricValueFromHistogram(histograms,
|
| + `${aggregateMetricPrefix}:${suffix}`);
|
| + assert.closeTo(aggregateMetric, subMetric1 + subMetric2, EPSILON7);
|
| + }
|
| });
|
|
|
| - // Process 1: There are two slices, each of length 50. The total bounds is
|
| - // 3000. Process 2: There is one slice of length 50.
|
| - // This yields total CPU time of 150ms, averaged over 3 seconds is 50ms.
|
| - test('cpuTimeMetric_twoProcesses', function() {
|
| - const sliceDuration = 50;
|
| - const totalDuration = 3000;
|
| - const value = computeCpuTime(function(model) {
|
| - model.rendererProcess = model.getOrCreateProcess(2);
|
| - model.rendererMain = model.rendererProcess.getOrCreateThread(3);
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: 0,
|
| - duration: sliceDuration,
|
| - cpuStart: 0,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - model.rendererMain.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: totalDuration - sliceDuration,
|
| - duration: sliceDuration,
|
| - cpuStart: totalDuration - sliceDuration,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| -
|
| - const otherProcess = model.getOrCreateProcess(3);
|
| - const otherThread = otherProcess.getOrCreateThread(4);
|
| - otherThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({
|
| - type: tr.model.ThreadSlice,
|
| - isTopLevel: true,
|
| - start: 0,
|
| - duration: sliceDuration,
|
| - cpuStart: 0,
|
| - cpuDuration: sliceDuration,
|
| - }));
|
| - });
|
| - assert.closeTo(value, 0.05, 0.001);
|
| + test('threadsAcrossMultipleProcessTypesAggregate', () => {
|
| + const modelSpec = {
|
| + processes: [
|
| + {
|
| + name: 'Browser',
|
| + pid: 12345,
|
| + threads: [
|
| + {
|
| + name: 'CrBrowserMain',
|
| + tid: 1,
|
| + slices: [],
|
| + },
|
| + ],
|
| + },
|
| + {
|
| + name: 'Renderer',
|
| + pid: 20001,
|
| + threads: [
|
| + {
|
| + name: 'Chrome_ChildIOThread',
|
| + tid: 42,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 20) {
|
| + slices.push({range:[i, i + 10], cpu: 5});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ],
|
| + },
|
| + {
|
| + name: 'GPU Process',
|
| + pid: 30001,
|
| + threads: [
|
| + {
|
| + name: 'Chrome_ChildIOThread',
|
| + tid: 52,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 100) {
|
| + slices.push({range:[i, i + 80], cpu: 40});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ]
|
| + },
|
| + ],
|
| +
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + expectations: [
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [0, 90]},
|
| +
|
| + {stage: 'Response', initiatorType: IT.CLICK, range: [200, 220]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [210, 260]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [250, 300]},
|
| +
|
| +
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [690, 890]},
|
| + ],
|
| + };
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const histograms = new tr.v.HistogramSet();
|
| + tr.metrics.sh.cpuTimeMetric(histograms, model);
|
| +
|
| + const subMetricPrefix1 =
|
| + 'cpuTime:Renderer:Chrome_ChildIOThread';
|
| + const subMetricPrefix2 =
|
| + 'cpuTime:GPU:Chrome_ChildIOThread';
|
| + const aggregateMetricPrefix =
|
| + 'cpuTime:all_processes:Chrome_ChildIOThread';
|
| +
|
| + function getMetricValueFromHistogram(histograms, metricName) {
|
| + return histograms.getHistogramNamed(fixMetricName(metricName)).sum;
|
| + }
|
| +
|
| + const metricSuffixes = [
|
| + // Single expectation range of same initiator type.
|
| + 'Animation:Video',
|
| + // Disjoint expectation ranges of same initiator type.
|
| + 'Animation:CSS',
|
| + // Overlapping expectation ranges of same initiator type.
|
| + 'Response:Scroll',
|
| + // Disjoint expectation ranges with all_initiators.
|
| + 'Animation:all_initiators',
|
| + // Overlapping expectation ranges with all_initiators.
|
| + 'Response:all_initiators',
|
| + // all_stages and all_initiators.
|
| + 'all_stages:all_initiators',
|
| + ]
|
| +
|
| + for (const suffix of metricSuffixes) {
|
| + const subMetricName1 = `${subMetricPrefix1}:${suffix}`;
|
| + const subMetricName2 = `${subMetricPrefix2}:${suffix}`;
|
| + const aggregateMetricName = `${aggregateMetricPrefix}:${suffix}`;
|
| + const subMetric1 = getMetricValueFromHistogram(histograms, subMetricName1);
|
| + const subMetric2 = getMetricValueFromHistogram(histograms, subMetricName2);
|
| + const aggregateMetric = getMetricValueFromHistogram(histograms,
|
| + aggregateMetricName);
|
| + assert.closeTo(aggregateMetric, subMetric1 + subMetric2, EPSILON7,
|
| + `${subMetricName1} and ${subMetricName2} aggregates to ` +
|
| + aggregateMetricName);
|
| + }
|
| + });
|
| +
|
| + test('completeAggregation', () => {
|
| + const modelSpec = {
|
| + processes: [
|
| + {
|
| + name: 'Browser',
|
| + pid: 12345,
|
| + threads: [
|
| + {
|
| + name: 'CrBrowserMain',
|
| + tid: 1,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 50) {
|
| + slices.push({range:[i, i + 50], cpu: 30});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ],
|
| + },
|
| + {
|
| + name: 'Renderer',
|
| + pid: 20001,
|
| + threads: [
|
| + {
|
| + name: 'Chrome_ChildIOThread',
|
| + tid: 42,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 20) {
|
| + slices.push({range:[i, i + 10], cpu: 5});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ],
|
| + },
|
| + {
|
| + name: 'GPU Process',
|
| + pid: 30001,
|
| + threads: [
|
| + {
|
| + name: 'Chrome_ChildIOThread',
|
| + tid: 52,
|
| + slices: (() => {
|
| + const slices = [];
|
| + for (let i = 0; i < 1000; i += 100) {
|
| + slices.push({range:[i, i + 80], cpu: 40});
|
| + }
|
| + return slices;
|
| + })(),
|
| + },
|
| + ]
|
| + },
|
| + ],
|
| +
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + expectations: [
|
| + {stage: 'Animation', initiatorType: IT.VIDEO, range: [0, 90]},
|
| +
|
| + {stage: 'Response', initiatorType: IT.CLICK, range: [200, 220]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [210, 260]},
|
| + {stage: 'Response', initiatorType: IT.SCROLL, range: [250, 300]},
|
| +
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: IT.CSS, range: [690, 890]},
|
| + ],
|
| + };
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const histograms = new tr.v.HistogramSet();
|
| + tr.metrics.sh.cpuTimeMetric(histograms, model);
|
| +
|
| + const metricName =
|
| + fixMetricName('cpuTime:all_processes:all_threads:all_stages:all_initiators');
|
| + const histogram = histograms.getHistogramNamed(metricName);
|
| + const metricValue = histogram.sum;
|
| +
|
| + assert.closeTo(metricValue, (30 * 20 + 5 * 50 + 40 * 10) / 1000, EPSILON7);
|
| });
|
| });
|
| </script>
|
|
|