| Index: tracing/tracing/extras/chrome/cpu_time_test.html
|
| diff --git a/tracing/tracing/extras/chrome/cpu_time_test.html b/tracing/tracing/extras/chrome/cpu_time_test.html
|
| index 177e2732653d2663910288bfbcb3b4890ec2ac27..86bf79978c41cbd32252374067d7156bf5083a03 100644
|
| --- a/tracing/tracing/extras/chrome/cpu_time_test.html
|
| +++ b/tracing/tracing/extras/chrome/cpu_time_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/cpu_time.html">
|
| +<link rel="import" href="/tracing/extras/chrome/cpu_time_test_utils.html">
|
|
|
| <script>
|
| 'use strict';
|
| @@ -17,6 +18,14 @@ tr.b.unittest.testSuite(function() {
|
|
|
| const INITIATOR_TYPE = tr.model.um.INITIATOR_TYPE;
|
|
|
| + const CHROME_PROCESS_NAMES =
|
| + tr.e.chrome.chrome_processes.CHROME_PROCESS_NAMES;
|
| +
|
| + const constructMultiDimensionalView =
|
| + tr.e.chrome.cpuTime.constructMultiDimensionalView;
|
| +
|
| + const buildModelFromSpec = tr.e.chrome.cpuTimeTestUtils.buildModelFromSpec;
|
| +
|
| test('getCpuTimeForThread', () => {
|
| const model = tr.c.TestUtils.newModel(function(model) {
|
| const thread = model.getOrCreateProcess(1).getOrCreateThread(1);
|
| @@ -76,7 +85,8 @@ tr.b.unittest.testSuite(function() {
|
| const allSegments = [...map.get('all_stages').get('all_initiators')];
|
| assert.sameDeepMembers(
|
| allSegments.map(s => [s.min, s.max]),
|
| - [[100, 300], [300, 400], [400, 600]]);
|
| + [[100, 300], [300, 400], [400, 600]]
|
| + );
|
|
|
| const videoAnimationSegments =
|
| [...map.get('Animation').get(INITIATOR_TYPE.VIDEO)];
|
| @@ -137,7 +147,8 @@ tr.b.unittest.testSuite(function() {
|
| const allSegments = [...map.get('all_stages').get('all_initiators')];
|
| assert.sameDeepMembers(
|
| allSegments.map(s => [s.min, s.max]),
|
| - [[150, 300], [300, 350]]);
|
| + [[150, 300], [300, 350]]
|
| + );
|
|
|
| const videoAnimationSegments =
|
| [...map.get('Animation').get(INITIATOR_TYPE.VIDEO)];
|
| @@ -160,5 +171,1361 @@ tr.b.unittest.testSuite(function() {
|
| // There should be no Response segments
|
| assert.isFalse(map.has('Response'));
|
| });
|
| +
|
| + /**
|
| + * Given the root node of a top down multidimensional tree view, returns
|
| + * the node at |path|.
|
| + */
|
| + function getNodeValues_(root, path) {
|
| + let node = root;
|
| + for (let i = 0; i < path.length; i++) {
|
| + for (const component of path[i]) {
|
| + node = node.children[i].get(component);
|
| + }
|
| + }
|
| + return node.values;
|
| + }
|
| +
|
| + const getCpuUsage_ = nodeValues => nodeValues[0].total;
|
| + const getCpuTotal_ = nodeValues => nodeValues[1].total;
|
| +
|
| + /**
|
| + * Returns a simple model spec with one process (browser process) and one
|
| + * thread (CrBrowserMain).
|
| + *
|
| + * It does not contain any slices or expectations - those should be added
|
| + * manually.
|
| + *
|
| + * This is a function instead of just a variable because the test functions
|
| + * are meant to modify this modelSpec and insert suitable expectations.
|
| + */
|
| + function getSimpleModelSpec_() {
|
| + return {
|
| + processes: [
|
| + {
|
| + name: 'Browser',
|
| + pid: 12345,
|
| + threads: [
|
| + {
|
| + name: 'CrBrowserMain',
|
| + tid: 1,
|
| + slices: []
|
| + },
|
| + ],
|
| + },
|
| + ],
|
| + expectations: [],
|
| + };
|
| + }
|
| +
|
| + test('constructMultiDimensionalView_' +
|
| + '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: INITIATOR_TYPE.CSS, range: [100, 300]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'CSS']];
|
| +
|
| + const model = buildModelFromSpec(simpleModelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // Total CPU Time is 30 + 20 from the two slices, and the total duration of
|
| + // CSS Animation expectation is 200 (because the range is [100, 300]). CPU
|
| + // Usage is therefore (30 + 20) / 200.
|
| + assert.closeTo(getCpuUsage_(values), (30 + 20) / 200, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), (30 + 20), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_' +
|
| + '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: INITIATOR_TYPE.VIDEO,
|
| + range: [75, 175]}
|
| + );
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'Video']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(simpleModelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // Only half of the first slice is in the expectation range, so we get a
|
| + // total CPU contribution of 30 / 2 = 15. The second slice is not in the
|
| + // expectation at all, so CPU contribution from that slice is 0. So total
|
| + // CPU Usage during Video Animation expectation is 15.
|
| + // The total duration of the expectation is 100, so CPU usage is 15 / 100.
|
| + assert.closeTo(getCpuUsage_(values), 15 / 100, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 15, 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_' +
|
| + '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: INITIATOR_TYPE.SCROLL,
|
| + range: [100, 160]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [205, 225]}
|
| + );
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Response', 'Scroll']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(simpleModelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // 1/5 of the first slice and 2/5 of the second slice is in the expectation
|
| + // ranges, so total CPU is 0.2 * 30 + 0.4 * 20.
|
| + // Total duration of Scroll Response expectation is 60 + 20, since the two
|
| + // expectation ranges are disjoint.
|
| + assert.closeTo(getCpuUsage_(values),
|
| + (0.2 * 30 + 0.4 * 20) / (60 + 20), 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + 0.2 * 30 + 0.4 * 20, 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_' +
|
| + 'singleThread-overlappingExpectationsOfSameInitiators', () => {
|
| + 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: INITIATOR_TYPE.CSS,
|
| + range: [100, 190]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [160, 230]}
|
| + );
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'CSS']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(simpleModelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // The whole of the first slice is covered by CSS Animation expectation,
|
| + // even though the expectations are from two different ranges. The second
|
| + // slice is only half covered. Total CPU usage: 30 + 0.5 * 20.
|
| + // The total range covered by the expectation is [100, 230], so total
|
| + // duration is 130.
|
| + assert.closeTo(getCpuUsage_(values), (30 + 0.5 * 20) / 130, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 30 + 0.5 * 20, 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_' +
|
| + '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: INITIATOR_TYPE.CSS,
|
| + range: [100, 190]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [160, 230]}
|
| + );
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(simpleModelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + (30 + 0.5 * 20) / 130, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + 30 + 0.5 * 20, 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_' +
|
| + '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: INITIATOR_TYPE.CSS,
|
| + range: [100, 190]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [160, 230]}
|
| + );
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['all_stages', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(simpleModelSpec);
|
| + const rangeOfInterest = new tr.b.math.Range.fromExplicitRange(100, 210);
|
| + const root = constructMultiDimensionalView(model, rangeOfInterest);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // Only 1/10 of the second slice is included in the range of interest, so
|
| + // contribution from that slice is 0.1 * 20.
|
| + // The total range of expectation within range of interest is [100, 210], so
|
| + // total duration is 110.
|
| + assert.closeTo(getCpuUsage_(values), (30 + 0.1 * 20) / 110, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 30 + 0.1 * 20, 1e-7);
|
| + });
|
| +
|
| + /**
|
| + * Returns a model spec where the browser process has two worker threads.
|
| + *
|
| + * This is a function instead of just a variable because the test functions
|
| + * are meant to modify this modelSpec and insert suitable expectations.
|
| + *
|
| + * Thread 1 looks like
|
| + *
|
| + * |0 |10 |20 |30 |40 |50 |60 |70 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 10ms and CPU time of 5ms.
|
| + *
|
| + * Thread 2 looks like
|
| + *
|
| + * |0 |50 |100 |150 |200 |250 |300 |350 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + * where each slice has a duration of 80ms and CPU time of 40ms.
|
| + */
|
| + function getMultipleThreadsOfSameTypeModelSpec_() {
|
| + return {
|
| + 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;
|
| + })(),
|
| + },
|
| + ],
|
| + },
|
| + ],
|
| +
|
| + expectations: [],
|
| + };
|
| + }
|
| +
|
| + test('constructMultiDimensionalView_multipleThreadsOfSameType_' +
|
| + 'singleExpectation', () => {
|
| + const modelSpec = getMultipleThreadsOfSameTypeModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Worker'], ['Animation', 'Video']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // There are five thread-1 slices within [0, 90] and one thread-2 slice.
|
| + assert.closeTo(getCpuUsage_(values), (5 * 5 + 40) / 90, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 5 * 5 + 40, 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_multipleThreadsOfSameType_' +
|
| + 'disjointExpectationSameInitiator', () => {
|
| + const modelSpec = getMultipleThreadsOfSameTypeModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Worker'], ['Animation', 'CSS']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + // Both worker threads are of the same type ('Worker'), so their CPU times
|
| + // will be added together.
|
| + // There are 3 thread-1 slices and 6/8 of a thread-2 slice within
|
| + // [500, 560].
|
| + // There are 1 thread-1 slices and two thread-2 slices within [690, 890].
|
| + // Total expectation duration is 60 + 200.
|
| + assert.closeTo(getCpuUsage_(values),
|
| + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)) / (60 + 200), 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + (5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_multipleThreadsOfSameType_' +
|
| + 'overlappingExpectationsOfSameInitiator', () => {
|
| + const modelSpec = getMultipleThreadsOfSameTypeModelSpec_();
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Worker'], ['Response', 'Scroll']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + (5 * 4 + 40 * (70 / 80)) / 90, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + 5 * 4 + 40 * (70 / 80), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_multipleThreadsOfSameType_' +
|
| + 'disjointExpectationsAllInitiators', () => {
|
| + const modelSpec = getMultipleThreadsOfSameTypeModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Worker'], ['Animation', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + ((5 * 5 + 40) + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2))) /
|
| + (90 + 60 + 200), 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + (5 * 5 + 40) + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)),
|
| + 1e-7);
|
| + });
|
| +
|
| +
|
| + test('constructMultiDimensionalView_multipleThreadsOfSameType_' +
|
| + 'overlappingExpectationsAllInitiators', () => {
|
| + const modelSpec = getMultipleThreadsOfSameTypeModelSpec_();
|
| + // [Click R]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Worker'], ['Response', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + (5 * 5 + 40) / 100, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + 5 * 5 + 40, 1e-7);
|
| + });
|
| +
|
| +
|
| + test('constructMultiDimensionalView_multipleThreadsOfSameType_' +
|
| + 'allStagesAllInitiators', () => {
|
| + const modelSpec = getMultipleThreadsOfSameTypeModelSpec_();
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Worker'], ['all_stages', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values), (250 + 400) / 990, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 250 + 400, 1e-7);
|
| + });
|
| +
|
| + /**
|
| + * Returns a model spec where there are two renderer processes, each with a
|
| + * renderer main thread.
|
| + *
|
| + * This is a function instead of just a variable because the test functions
|
| + * are meant to modify this modelSpec and insert suitable expectations.
|
| + *
|
| + * The main thread on renderer-1 looks like
|
| + *
|
| + * |0 |10 |20 |30 |40 |50 |60 |70 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 10ms and CPU time of 5ms.
|
| + *
|
| + * The main thread on renderer-2 looks like
|
| + *
|
| + * |0 |50 |100 |150 |200 |250 |300 |350 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 80ms and CPU time of 40ms.
|
| + */
|
| + function getMultipleProcessesOfSameTypeModelSpec_() {
|
| + return {
|
| + 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;
|
| + })(),
|
| + },
|
| + ]
|
| + },
|
| + ],
|
| +
|
| + expectations: [],
|
| + };
|
| + }
|
| +
|
| + test('constructMultiDimensionalView_multipleProcessesOfSameType_' +
|
| + 'singleExpectation', () => {
|
| + const modelSpec = getMultipleProcessesOfSameTypeModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['CrRendererMain'], ['Animation', 'Video']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values), (5 * 5 + 40) / 90, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 5 * 5 + 40, 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_multipleProcessesOfSameType_' +
|
| + 'disjointExpectationSameInitiator', () => {
|
| + const modelSpec = getMultipleProcessesOfSameTypeModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['CrRendererMain'], ['Animation', 'CSS']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)) / (60 + 200), 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + (5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_multipleProcessesOfSameType_' +
|
| + 'overlappingExpectationsOfSameInitiator', () => {
|
| + const modelSpec = getMultipleProcessesOfSameTypeModelSpec_();
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['CrRendererMain'], ['Response', 'Scroll']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + (5 * 4 + 40 * (70 / 80)) / 90, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + 5 * 4 + 40 * (70 / 80), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_multipleProcessesOfSameType_' +
|
| + 'disjointExpectationsAllInitiators', () => {
|
| + const modelSpec = getMultipleProcessesOfSameTypeModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['CrRendererMain'], ['Animation', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + ((5 * 5 + 40) + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2))) /
|
| + (90 + 60 + 200), 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + (5 * 5 + 40) + ((5 * 3 + 40 * (60 / 80)) + (5 * 10 + 40 * 2)),
|
| + 1e-7);
|
| + });
|
| +
|
| +
|
| + test('constructMultiDimensionalView_multipleProcessesOfSameType_' +
|
| + 'overlappingExpectationsAllInitiators', () => {
|
| + const modelSpec = getMultipleProcessesOfSameTypeModelSpec_();
|
| + // [Click R]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['CrRendererMain'], ['Response', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values), (5 * 5 + 40) / 100, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 5 * 5 + 40, 1e-7);
|
| + });
|
| +
|
| +
|
| + test('constructMultiDimensionalView_multipleProcessesOfSameType_' +
|
| + 'allStagesAllInitiators', () => {
|
| + const modelSpec = getMultipleProcessesOfSameTypeModelSpec_();
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const path = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['CrRendererMain'], ['all_stages', 'all_initiators']
|
| + ];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values), (250 + 400) / 990, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values), 250 + 400, 1e-7);
|
| + });
|
| +
|
| + /**
|
| + * Returns a model spec where the browser process has a main thread and an IO
|
| + * thread.
|
| + *
|
| + * This is a function instead of just a variable because the test functions
|
| + * are meant to modify this modelSpec and insert suitable expectations.
|
| + *
|
| + * The browser main thread looks like
|
| + *
|
| + * |0 |10 |20 |30 |40 |50 |60 |70 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 10ms and CPU time of 5ms.
|
| + *
|
| + * The IO Thread looks like
|
| + *
|
| + * |0 |50 |100 |150 |200 |250 |300 |350 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 80ms and CPU time of 40ms.
|
| + */
|
| + function getAllThreadsOfSameProcessModelSpec_() {
|
| + return {
|
| + 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;
|
| + })(),
|
| + }
|
| + ],
|
| + },
|
| + ],
|
| +
|
| + expectations: [],
|
| + };
|
| + }
|
| +
|
| +
|
| + test('constructMultiDimensionalView_AllThreadsOfSameProcess_' +
|
| + 'singleExpectation', () => {
|
| + const modelSpec = getAllThreadsOfSameProcessModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [CHROME_PROCESS_NAMES.BROWSER], [], ['Animation', 'Video']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'Video']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Chrome_IOThread'], ['Animation', 'Video']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllThreadsOfSameProcess_' +
|
| + 'disjointExpectationSameInitiator', () => {
|
| + const modelSpec = getAllThreadsOfSameProcessModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [CHROME_PROCESS_NAMES.BROWSER], [], ['Animation', 'CSS']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'CSS']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Chrome_IOThread'], ['Animation', 'CSS']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllThreadsOfSameProcess_' +
|
| + 'overlappingExpectationsOfSameInitiator', () => {
|
| + const modelSpec = getAllThreadsOfSameProcessModelSpec_();
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [CHROME_PROCESS_NAMES.BROWSER], [], ['Response', 'Scroll']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Response', 'Scroll']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Chrome_IOThread'], ['Response', 'Scroll']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllThreadsOfSameProcess_' +
|
| + 'disjointExpectationsAllInitiators', () => {
|
| + const modelSpec = getAllThreadsOfSameProcessModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [CHROME_PROCESS_NAMES.BROWSER], [], ['Animation', 'all_initiators']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Animation', 'all_initiators']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Chrome_IOThread'], ['Animation', 'all_initiators']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllThreadsOfSameProcess_' +
|
| + 'overlappingExpectationsAllInitiators', () => {
|
| + const modelSpec = getAllThreadsOfSameProcessModelSpec_();
|
| + // [Click R]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [CHROME_PROCESS_NAMES.BROWSER], [], ['Response', 'all_initiators']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['Response', 'all_initiators']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Chrome_IOThread'], ['Response', 'all_initiators']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllThreadsOfSameProcess_' +
|
| + 'allStagesAllInitiators', () => {
|
| + const modelSpec = getAllThreadsOfSameProcessModelSpec_();
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [CHROME_PROCESS_NAMES.BROWSER], [], ['all_stages', 'all_initiators']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['CrBrowserMain'], ['all_stages', 'all_initiators']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.BROWSER],
|
| + ['Chrome_IOThread'], ['all_stages', 'all_initiators']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + /**
|
| + * Returns a model spec where a renderer process and a GPU process both have a
|
| + * Chrome_ChildIOThread.
|
| + *
|
| + * This is a function instead of just a variable because the test functions
|
| + * are meant to modify this modelSpec and insert suitable expectations.
|
| + *
|
| + * The modelSpec includes a basic browser process because it not a valid
|
| + * chrome model otherwise.
|
| + *
|
| + * The renderer ChildIOThread looks like
|
| + *
|
| + * |0 |10 |20 |30 |40 |50 |60 |70 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 10ms and CPU time of 5ms.
|
| + *
|
| + * The GPU ChildIOThread looks like
|
| + *
|
| + * |0 |50 |100 |150 |200 |250 |300 |350 .... Time
|
| + * [ ] [ ] [ ] [ ] .... Slices
|
| + *
|
| + * where each slice has a duration of 80ms and CPU time of 40ms.
|
| + */
|
| + function getAllProcessesOfSameThreadModelSpec_() {
|
| + return {
|
| + 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;
|
| + })(),
|
| + },
|
| + ]
|
| + },
|
| + ],
|
| + expectations: [],
|
| + };
|
| + }
|
| +
|
| + test('constructMultiDimensionalView_AllProcessesOfSameThread_' +
|
| + 'singleExpectation', () => {
|
| + const modelSpec = getAllProcessesOfSameThreadModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [], ['Chrome_ChildIOThread'], ['Animation', 'Video']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['Chrome_ChildIOThread'], ['Animation', 'Video']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.GPU],
|
| + ['Chrome_ChildIOThread'], ['Animation', 'Video']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllProcessesOfSameThread_' +
|
| + 'disjointExpectationSameInitiator', () => {
|
| + const modelSpec = getAllProcessesOfSameThreadModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [], ['Chrome_ChildIOThread'], ['Animation', 'CSS']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['Chrome_ChildIOThread'], ['Animation', 'CSS']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.GPU],
|
| + ['Chrome_ChildIOThread'], ['Animation', 'CSS']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllProcessesOfSameThread_' +
|
| + 'overlappingExpectationsOfSameInitiator', () => {
|
| + const modelSpec = getAllProcessesOfSameThreadModelSpec_();
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [], ['Chrome_ChildIOThread'], ['Response', 'Scroll']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['Chrome_ChildIOThread'], ['Response', 'Scroll']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.GPU],
|
| + ['Chrome_ChildIOThread'], ['Response', 'Scroll']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| +
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllProcessesOfSameThread_' +
|
| + 'disjointExpectationsAllInitiators', () => {
|
| + const modelSpec = getAllProcessesOfSameThreadModelSpec_();
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [], ['Chrome_ChildIOThread'], ['Animation', 'all_initiators']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['Chrome_ChildIOThread'], ['Animation', 'all_initiators']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.GPU],
|
| + ['Chrome_ChildIOThread'], ['Animation', 'all_initiators']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllProcessesOfSameThread_' +
|
| + 'overlappingExpectationsAllInitiators', () => {
|
| + const modelSpec = getAllProcessesOfSameThreadModelSpec_();
|
| + // [Click R]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [], ['Chrome_ChildIOThread'], ['Response', 'all_initiators']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['Chrome_ChildIOThread'], ['Response', 'all_initiators']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.GPU],
|
| + ['Chrome_ChildIOThread'], ['Response', 'all_initiators']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_AllProcessesOfSameThread_' +
|
| + 'allStagesAllInitiators', () => {
|
| + const modelSpec = getAllProcessesOfSameThreadModelSpec_();
|
| + // [Video A] [Click R] [CSS A] [ CSS A ]
|
| + // [Scroll R]
|
| + // [Scroll R]
|
| + modelSpec.expectations.push(
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + );
|
| +
|
| + const pathForAllThreads = [
|
| + [], ['Chrome_ChildIOThread'], ['all_stages', 'all_initiators']];
|
| +
|
| + const pathForThread1 = [
|
| + [CHROME_PROCESS_NAMES.RENDERER],
|
| + ['Chrome_ChildIOThread'], ['all_stages', 'all_initiators']];
|
| +
|
| + const pathForThread2 = [
|
| + [CHROME_PROCESS_NAMES.GPU],
|
| + ['Chrome_ChildIOThread'], ['all_stages', 'all_initiators']];
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const valueForAllThreads = getNodeValues_(root, pathForAllThreads);
|
| + const valueForThread1 = getNodeValues_(root, pathForThread1);
|
| + const valueForThread2 = getNodeValues_(root, pathForThread2);
|
| +
|
| + assert.closeTo(getCpuUsage_(valueForAllThreads),
|
| + getCpuUsage_(valueForThread1) + getCpuUsage_(valueForThread2), 1e-7);
|
| + assert.closeTo(getCpuTotal_(valueForAllThreads),
|
| + getCpuTotal_(valueForThread1) + getCpuTotal_(valueForThread2), 1e-7);
|
| + });
|
| +
|
| + test('constructMultiDimensionalView_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: INITIATOR_TYPE.VIDEO,
|
| + range: [0, 90]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.CLICK,
|
| + range: [200, 220]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [210, 260]},
|
| + {stage: 'Response', initiatorType: INITIATOR_TYPE.SCROLL,
|
| + range: [250, 300]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [500, 560]},
|
| + {stage: 'Animation', initiatorType: INITIATOR_TYPE.CSS,
|
| + range: [690, 890]}
|
| + ],
|
| + };
|
| +
|
| + const model = buildModelFromSpec(modelSpec);
|
| + const path = [[], [], ['all_stages', 'all_initiators']];
|
| + const root = constructMultiDimensionalView(model, model.bounds);
|
| + const values = getNodeValues_(root, path);
|
| +
|
| + assert.closeTo(getCpuUsage_(values),
|
| + (30 * 20 + 5 * 50 + 40 * 10) / 1000, 1e-7);
|
| + assert.closeTo(getCpuTotal_(values),
|
| + (30 * 20 + 5 * 50 + 40 * 10), 1e-7);
|
| + });
|
| });
|
| +
|
| </script>
|
|
|