| <!DOCTYPE html> |
| <!-- |
| Copyright 2017 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/core/test_utils.html"> |
| <link rel="import" href="/tracing/extras/chrome/event_finder_utils.html"> |
| <link rel="import" href="/tracing/metrics/system_health/loading_metric.html"> |
| <link rel="import" href="/tracing/value/histogram_set.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| const rendererPid = 12345; |
| const model = tr.c.TestUtils.newModel(function(model) { |
| const rendererProcess = model.getOrCreateProcess(rendererPid); |
| const mainThread = rendererProcess.getOrCreateThread(2); |
| mainThread.name = 'CrRendererMain'; |
| |
| // Our main thread looks like: |
| // |
| // [ parseHTML ] [ layout ] [ V8.Exec ] |
| // | [ V8.Exec ] | | | | [ layout ] | |
| // | | | | | | | | | | |
| // | | | | | | | | | | |
| // v v v v v v v v v v |
| // Ts: 200 250 300 400 450 550 570 600 620 650 |
| // Cpu:1160 1200 1240 1320 1360 1440 1456 1480 1496 1520 |
| |
| // Add layout categories |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'blink', |
| title: 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser', |
| start: 200, |
| duration: 200, |
| cpuStart: 1160, |
| cpuDuration: 160, |
| })); |
| |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'devtools.timeline', |
| title: 'Script', |
| start: 250, |
| duration: 50, |
| cpuStart: 1200, |
| cpuDuration: 40, |
| })); |
| |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'v8', |
| title: 'V8.Execute', |
| start: 250, |
| duration: 50, |
| args: {'runtime-call-stat': '{"ICMiss": [3, 150], "GC": [10, 60]}'}, |
| cpuStart: 1200, |
| cpuDuration: 40, |
| })); |
| |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'blink', |
| title: 'LocalFrameView::layout', |
| start: 450, |
| duration: 100, |
| cpuStart: 1360, |
| cpuDuration: 80, |
| })); |
| |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'v8', |
| title: 'V8.Execute', |
| start: 570, |
| duration: 80, |
| args: {'runtime-call-stat': '{"DeOptimize": [1, 42], "GC": [3, 50]}'}, |
| cpuStart: 1456, |
| cpuDuration: 64, |
| })); |
| |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'blink', |
| title: 'WebViewImpl::updateAllLifecyclePhases', |
| start: 600, |
| duration: 20, |
| cpuStart: 1480, |
| cpuDuration: 16, |
| })); |
| }); |
| |
| const chromeHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper); |
| |
| const rendererHelper = chromeHelper.rendererHelpers[rendererPid]; |
| |
| test('testWallClockTimeBreakdownNoIntersectingBoundary', function() { |
| const rangeOfInterest = tr.b.math.Range.fromExplicitRange(0, 1000); |
| const networkEvents = tr.e.chrome.EventFinderUtils.getNetworkEventsInRange( |
| rendererHelper.process, rangeOfInterest); |
| const breakdownTree = tr.metrics.sh.generateWallClockTimeBreakdownTree( |
| rendererHelper.mainThread, networkEvents, rangeOfInterest); |
| assert.deepEqual({ |
| total: 150, |
| events: { |
| 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser': 150 |
| } |
| }, breakdownTree.parseHTML); |
| assert.deepEqual({ |
| total: 120, |
| events: { |
| 'LocalFrameView::layout': 100, |
| 'WebViewImpl::updateAllLifecyclePhases': 20, |
| } |
| }, breakdownTree.layout); |
| assert.deepEqual({ |
| total: 110, |
| events: { |
| 'V8.Execute': 110, |
| } |
| }, breakdownTree.script_execute); |
| assert.deepEqual({ |
| total: 0.302, |
| events: { |
| 'DeOptimize': 0.042, |
| 'GC': 0.11, |
| 'ICMiss': 0.15, |
| } |
| }, breakdownTree.v8_runtime); |
| }); |
| |
| test('testWallClockTimeBreakdownIntersectingBoundary', function() { |
| // Our main thread looks like: |
| // |
| // [ parseHTML ] [ layout ] [ V8.Exec ] |
| // | [ V8.Exec ] | | | | [ layout ] | |
| // | | | | | | | | | | |
| // | | | | | | | | | | |
| // v v v v v v v v v v |
| // Ts: 200 250 300 400 450 550 570 600 620 650 |
| // | | |
| // 275 610 |
| const rangeOfInterest = tr.b.math.Range.fromExplicitRange(275, 610); |
| const networkEvents = tr.e.chrome.EventFinderUtils.getNetworkEventsInRange( |
| rendererHelper.process, rangeOfInterest); |
| const breakdownTree = tr.metrics.sh.generateWallClockTimeBreakdownTree( |
| rendererHelper.mainThread, networkEvents, rangeOfInterest); |
| assert.deepEqual({ |
| total: 100, |
| events: { |
| 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser': 100 |
| } |
| }, breakdownTree.parseHTML); |
| assert.deepEqual({ |
| total: 110, |
| events: { |
| 'LocalFrameView::layout': 100, |
| 'WebViewImpl::updateAllLifecyclePhases': 10, |
| } |
| }, breakdownTree.layout); |
| assert.deepEqual({ |
| total: 55, |
| events: { |
| 'V8.Execute': 55, |
| } |
| }, breakdownTree.script_execute); |
| assert.deepEqual({ |
| total: 0.151, |
| events: { |
| 'DeOptimize': 0.021, |
| 'GC': 0.055, |
| 'ICMiss': 0.075, |
| } |
| }, breakdownTree.v8_runtime); |
| }); |
| |
| test('testCpuTimeBreakdownNoIntersectingBoundary', function() { |
| const rangeOfInterest = tr.b.math.Range.fromExplicitRange(100, 800); |
| const breakdownTree = tr.metrics.sh.generateCpuTimeBreakdownTree( |
| rendererHelper.mainThread, |
| rangeOfInterest); |
| assert.deepEqual({ |
| total: 120, |
| events: { |
| 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser': 120 |
| } |
| }, breakdownTree.parseHTML); |
| assert.deepEqual({ |
| total: 96, |
| events: { |
| 'LocalFrameView::layout': 80, |
| 'WebViewImpl::updateAllLifecyclePhases': 16, |
| } |
| }, breakdownTree.layout); |
| assert.deepEqual({ |
| total: 88, |
| events: { |
| 'V8.Execute': 88, |
| } |
| }, breakdownTree.script_execute); |
| assert.deepEqual({ |
| total: 0.302, |
| events: { |
| 'DeOptimize': 0.042, |
| 'GC': 0.11, |
| 'ICMiss': 0.15, |
| } |
| }, breakdownTree.v8_runtime); |
| }); |
| |
| test('testCpuTimeBreakdownIntersectingBoundary', function() { |
| // Our main thread looks like: |
| // |
| // [ parseHTML ] [ layout ] [ V8.Exec ] |
| // | [ V8.Exec ] | | | | [ layout ] | |
| // | | | | | | | | | | |
| // | | | | | | | | | | |
| // v v v v v v v v v v |
| // Ts: 200 250 300 400 450 550 570 600 620 650 |
| // Cpu:1160 1200 1240 1320 1360 1440 1456 1480 1496 1520 |
| // [ ] |
| // Ts RoI 275 610 |
| const rangeOfInterest = tr.b.math.Range.fromExplicitRange(275, 610); |
| const breakdownTree = tr.metrics.sh.generateCpuTimeBreakdownTree( |
| rendererHelper.mainThread, |
| rangeOfInterest); |
| assert.deepEqual({ |
| total: 80, |
| events: { |
| 'HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser': 80 |
| } |
| }, breakdownTree.parseHTML); |
| assert.deepEqual({ |
| total: 88, |
| events: { |
| 'LocalFrameView::layout': 80, |
| 'WebViewImpl::updateAllLifecyclePhases': 8, |
| } |
| }, breakdownTree.layout); |
| assert.deepEqual({ |
| total: 44, |
| events: { |
| 'V8.Execute': 44, |
| } |
| }, breakdownTree.script_execute); |
| assert.deepEqual({ |
| total: 0.151, |
| events: { |
| 'DeOptimize': 0.021, |
| 'GC': 0.055, |
| 'ICMiss': 0.075 |
| } |
| }, breakdownTree.v8_runtime); |
| }); |
| |
| function createNetworkEvent(start, end, cat) { |
| return tr.c.TestUtils.newAsyncSliceEx({ |
| cat, |
| title: 'network events', |
| start, |
| duration: end - start, |
| }); |
| } |
| |
| test('testBlockedOnNetwork_onlyNetEvent', function() { |
| const model = tr.c.TestUtils.newModel(model => { |
| const mainThread = model.getOrCreateProcess(0) |
| .getOrCreateThread(0); |
| mainThread.name = 'CrRendererMain'; |
| const networkEvent = createNetworkEvent(100, 200, 'net'); |
| mainThread.asyncSliceGroup.push(networkEvent); |
| }); |
| const rendererHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper) |
| .rendererHelpers[0]; |
| const rangeOfInterest = tr.b.math.Range.fromExplicitRange(0, 150); |
| const networkEvents = tr.e.chrome.EventFinderUtils.getNetworkEventsInRange( |
| rendererHelper.process, rangeOfInterest); |
| const breakdownTree = tr.metrics.sh.generateWallClockTimeBreakdownTree( |
| rendererHelper.mainThread, networkEvents, rangeOfInterest); |
| assert.strictEqual(breakdownTree.blocked_on_network.total, 50); |
| assert.strictEqual(breakdownTree.idle.total, 100); |
| }); |
| |
| test('testBlockedOnNetwork_netEventAndMainThreadEvent', function() { |
| const model = tr.c.TestUtils.newModel(model => { |
| const mainThread = model.getOrCreateProcess(0) |
| .getOrCreateThread(0); |
| mainThread.name = 'CrRendererMain'; |
| const networkEvent = createNetworkEvent(100, 200, 'net'); |
| mainThread.asyncSliceGroup.push(networkEvent); |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'blink', |
| title: 'LocalFrameView::layout', |
| start: 160, |
| duration: 140, |
| })); |
| }); |
| const rendererHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper) |
| .rendererHelpers[0]; |
| const rangeOfInterest = tr.b.math.Range.fromExplicitRange(150, 320); |
| const networkEvents = tr.e.chrome.EventFinderUtils.getNetworkEventsInRange( |
| rendererHelper.process, rangeOfInterest); |
| const breakdownTree = tr.metrics.sh.generateWallClockTimeBreakdownTree( |
| rendererHelper.mainThread, networkEvents, rangeOfInterest); |
| assert.strictEqual(breakdownTree.layout.total, 140); |
| assert.strictEqual(breakdownTree.blocked_on_network.total, 10); |
| assert.strictEqual(breakdownTree.idle.total, 20); |
| }); |
| |
| test('testBlockedOnNetwork_rangeEmpty', function() { |
| const model = tr.c.TestUtils.newModel(model => { |
| const mainThread = model.getOrCreateProcess(0) |
| .getOrCreateThread(0); |
| mainThread.name = 'CrRendererMain'; |
| const networkEvent = createNetworkEvent(100, 200, 'net'); |
| mainThread.asyncSliceGroup.push(networkEvent); |
| mainThread.sliceGroup.pushSlice(tr.c.TestUtils.newSliceEx({ |
| cat: 'blink', |
| title: 'FrameView::layout', |
| start: 160, |
| duration: 140, |
| })); |
| }); |
| const rendererHelper = model.getOrCreateHelper( |
| tr.model.helpers.ChromeModelHelper) |
| .rendererHelpers[0]; |
| const rangeOfInterest = new tr.b.math.Range(); |
| const networkEvents = tr.e.chrome.EventFinderUtils.getNetworkEventsInRange( |
| rendererHelper.process, rangeOfInterest); |
| const breakdownTree = tr.metrics.sh.generateWallClockTimeBreakdownTree( |
| rendererHelper.mainThread, networkEvents, rangeOfInterest); |
| assert.strictEqual(breakdownTree.layout.total, 0); |
| assert.strictEqual(breakdownTree.blocked_on_network.total, 0); |
| assert.strictEqual(breakdownTree.idle.total, 0); |
| }); |
| }); |
| </script> |