| 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 73220e63b8352c7de2de4566ffa44d56cf1542c7..0f25f047226e9c322be09c5d956384f108e0af78 100644
|
| --- a/tracing/tracing/extras/chrome/cpu_time_test.html
|
| +++ b/tracing/tracing/extras/chrome/cpu_time_test.html
|
| @@ -7,11 +7,25 @@ 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';
|
|
|
| tr.b.unittest.testSuite(function() {
|
| + const getStageToInitiatorToSegmentBounds =
|
| + tr.e.chrome.cpuTime.getStageToInitiatorToSegmentBounds;
|
| +
|
| + 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);
|
| @@ -41,5 +55,1394 @@ tr.b.unittest.testSuite(function() {
|
| assert.closeTo(tr.e.chrome.cpuTime.getCpuTimeForThread(thread, bounds),
|
| expectedCpuTime, 1e-7);
|
| });
|
| +
|
| + test('getStageToInitiatorToSegmentBounds', () => {
|
| + const model = tr.c.TestUtils.newModel(function(model) {
|
| + const thread = model.getOrCreateProcess(1).getOrCreateThread(1);
|
| + // This is needed for a model to have segments.
|
| + thread.name = 'CrBrowserMain';
|
| +
|
| + model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
|
| + model, INITIATOR_TYPE.CSS,
|
| + 100, // start time.
|
| + 300 // duration.
|
| + ));
|
| + model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
|
| + model, INITIATOR_TYPE.VIDEO, 300, 100));
|
| + model.userModel.expectations.push(new tr.model.um.ResponseExpectation(
|
| + model, INITIATOR_TYPE.SCROLL, 400, 200));
|
| + });
|
| +
|
| + const segments = model.userModel.segments;
|
| +
|
| + const map = getStageToInitiatorToSegmentBounds(
|
| + model.userModel.segments, model.bounds);
|
| +
|
| + // Ignoring Idle Expectations, we have the following segments:
|
| + // [100, 300]: CSS Animation
|
| + // [300, 400]: CSS Animation, Video Animation
|
| + // [400, 600]: Scroll Response
|
| + const allSegments = [...map.get('all_stages').get('all_initiators')];
|
| + assert.sameDeepMembers(
|
| + allSegments.map(s => [s.min, s.max]),
|
| + [[100, 300], [300, 400], [400, 600]]
|
| + );
|
| +
|
| + const videoAnimationSegments =
|
| + [...map.get('Animation').get(INITIATOR_TYPE.VIDEO)];
|
| + assert.sameDeepMembers(
|
| + videoAnimationSegments.map(s => [s.min, s.max]),
|
| + [[300, 400]]);
|
| +
|
| + const cssAnimationSegments =
|
| + [...map.get('Animation').get(INITIATOR_TYPE.CSS)];
|
| + assert.sameDeepMembers(
|
| + cssAnimationSegments.map(s => [s.min, s.max]),
|
| + [[100, 300], [300, 400]]);
|
| +
|
| + const allAnimationSegments =
|
| + [...map.get('Animation').get('all_initiators')];
|
| + assert.sameDeepMembers(
|
| + allAnimationSegments.map(s => [s.min, s.max]),
|
| + [[100, 300], [300, 400]]);
|
| +
|
| + const scrollResponseSegments =
|
| + [...map.get('Response').get(INITIATOR_TYPE.SCROLL)];
|
| + assert.sameDeepMembers(
|
| + scrollResponseSegments.map(s => [s.min, s.max]),
|
| + [[400, 600]]);
|
| +
|
| + const allResponseSegments =
|
| + [...map.get('Response').get('all_initiators')];
|
| + assert.sameDeepMembers(
|
| + allResponseSegments.map(s => [s.min, s.max]),
|
| + [[400, 600]]);
|
| + });
|
| +
|
| + test('getStageToInitiatorToSegmentBounds-rangeOfInterest', () => {
|
| + const model = tr.c.TestUtils.newModel(function(model) {
|
| + const thread = model.getOrCreateProcess(1).getOrCreateThread(1);
|
| + // This is needed for a model to have segments.
|
| + thread.name = 'CrBrowserMain';
|
| +
|
| + model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
|
| + model, INITIATOR_TYPE.CSS,
|
| + 100, // start time.
|
| + 300 // duration.
|
| + ));
|
| + model.userModel.expectations.push(new tr.model.um.AnimationExpectation(
|
| + model, INITIATOR_TYPE.VIDEO, 300, 100));
|
| + model.userModel.expectations.push(new tr.model.um.ResponseExpectation(
|
| + model, INITIATOR_TYPE.SCROLL, 400, 200));
|
| + });
|
| +
|
| + const segments = model.userModel.segments;
|
| +
|
| + const map = getStageToInitiatorToSegmentBounds(model.userModel.segments,
|
| + tr.b.math.Range.fromExplicitRange(150, 350));
|
| +
|
| + // Ignoring Idle Expectations, we have the following segments in range:
|
| + // [150, 300]: CSS Animation
|
| + // [300, 350]: CSS Animation, Video Animation
|
| + const allSegments = [...map.get('all_stages').get('all_initiators')];
|
| + assert.sameDeepMembers(
|
| + allSegments.map(s => [s.min, s.max]),
|
| + [[150, 300], [300, 350]]
|
| + );
|
| +
|
| + const videoAnimationSegments =
|
| + [...map.get('Animation').get(INITIATOR_TYPE.VIDEO)];
|
| + assert.sameDeepMembers(
|
| + videoAnimationSegments.map(s => [s.min, s.max]),
|
| + [[300, 350]]);
|
| +
|
| + const cssAnimationSegments =
|
| + [...map.get('Animation').get(INITIATOR_TYPE.CSS)];
|
| + assert.sameDeepMembers(
|
| + cssAnimationSegments.map(s => [s.min, s.max]),
|
| + [[150, 300], [300, 350]]);
|
| +
|
| + const allAnimationSegments =
|
| + [...map.get('Animation').get('all_initiators')];
|
| + assert.sameDeepMembers(
|
| + allAnimationSegments.map(s => [s.min, s.max]),
|
| + [[150, 300], [300, 350]]);
|
| +
|
| + // There should be no Response segments
|
| + assert.isFalse(map.has('Response'));
|
| + });
|
| +
|
| + /**
|
| + * Given the root node of a top down multidimensional tree view, and returns
|
| + * the node at |path|.
|
| + */
|
| + function getNodeValues_(root, path) {
|
| + let node = root;
|
| + for (let i = 0; i <= 2; 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);
|
| +
|
| + 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);
|
| +
|
| + 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);
|
| +
|
| + 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);
|
| +
|
| + 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);
|
| +
|
| + 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.
|
| + */
|
| + 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);
|
| +
|
| + 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);
|
| +
|
| + 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.
|
| + */
|
| + 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.
|
| + */
|
| + 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.
|
| + */
|
| + 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>
|
|
|