From 33b1574da7a404e2ad701ea9651b08a6e40245c7 Mon Sep 17 00:00:00 2001 From: Paul Irish Date: Fri, 17 Nov 2017 13:27:27 -0800 Subject: [PATCH] core(bootup-time): refactor task/group iteration --- lighthouse-core/audits/bootup-time.js | 67 ++++++++----------- .../test/audits/bootup-time-test.js | 28 ++++---- 2 files changed, 43 insertions(+), 52 deletions(-) diff --git a/lighthouse-core/audits/bootup-time.js b/lighthouse-core/audits/bootup-time.js index 36fd5777e871..842a3c1541d5 100644 --- a/lighthouse-core/audits/bootup-time.js +++ b/lighthouse-core/audits/bootup-time.js @@ -114,22 +114,25 @@ class BootupTime extends Audit { */ static getExecutionTimingsByURL(trace) { const timelineModel = new DevtoolsTimelineModel(trace); - const bottomUpByName = timelineModel.bottomUpGroupBy('URL'); + const bottomUpByURL = timelineModel.bottomUpGroupBy('URL'); const result = new Map(); - bottomUpByName.children.forEach((perUrlNode, url) => { + bottomUpByURL.children.forEach((perUrlNode, url) => { // when url is "" or about:blank, we skip it if (!url || url === 'about:blank') { return; } - const tasks = {}; + const taskGroups = {}; perUrlNode.children.forEach((perTaskPerUrlNode) => { - const taskGroup = WebInspector.TimelineUIUtils.eventStyle(perTaskPerUrlNode.event); - tasks[taskGroup.title] = tasks[taskGroup.title] || 0; - tasks[taskGroup.title] += Number((perTaskPerUrlNode.selfTime || 0).toFixed(1)); + // eventStyle() returns a string like 'Evaluate Script' + const task = WebInspector.TimelineUIUtils.eventStyle(perTaskPerUrlNode.event); + // Resolve which taskGroup we're using + const groupName = taskToGroup[task.title] || group.other; + const groupTotal = taskGroups[groupName] || 0; + taskGroups[groupName] = groupTotal + (perTaskPerUrlNode.selfTime || 0); }); - result.set(url, tasks); + result.set(url, taskGroups); }); return result; @@ -141,50 +144,34 @@ class BootupTime extends Audit { */ static audit(artifacts) { const trace = artifacts.traces[BootupTime.DEFAULT_PASS]; - const bootupTimings = BootupTime.getExecutionTimingsByURL(trace); + const executionTimings = BootupTime.getExecutionTimingsByURL(trace); let totalBootupTime = 0; const extendedInfo = {}; + const headings = [ {key: 'url', itemType: 'url', text: 'URL'}, + {key: 'scripting', itemType: 'text', text: group.scripting}, + {key: 'scriptParseCompile', itemType: 'text', text: group.scriptParseCompile}, ]; - // Group tasks per url - const groupsPerUrl = Array.from(bootupTimings).map(([url, durations]) => { - extendedInfo[url] = durations; - - const groups = []; - Object.keys(durations).forEach(task => { - totalBootupTime += durations[task]; - const group = taskToGroup[task]; - - groups[group] = groups[group] || 0; - groups[group] += durations[task]; - - if (!headings.find(heading => heading.key === group)) { - headings.push( - {key: group, itemType: 'text', text: group} - ); - } - }); + // map data in correct format to create a table + const results = Array.from(executionTimings).map(([url, groups]) => { + // Add up the totalBootupTime for all the taskGroups + totalBootupTime += Object.keys(groups).reduce((sum, name) => sum += groups[name], 0); + extendedInfo[url] = groups; + const scriptingTotal = groups[group.scripting] || 0; + const parseCompileTotal = groups[group.scriptParseCompile] || 0; return { url: url, - groups, + sum: scriptingTotal + parseCompileTotal, + // Only reveal the javascript task costs + // Later we can account for forced layout costs, etc. + scripting: Util.formatMilliseconds(scriptingTotal, 1), + scriptParseCompile: Util.formatMilliseconds(parseCompileTotal, 1), }; - }); - - // map data in correct format to create a table - const results = groupsPerUrl.map(({url, groups}) => { - const res = {}; - headings.forEach(heading => { - res[heading.key] = Util.formatMilliseconds(groups[heading.key] || 0, 1); - }); - - res.url = url; - - return res; - }); + }).sort((a, b) => b.sum - a.sum); const tableDetails = BootupTime.makeTableDetails(headings, results); diff --git a/lighthouse-core/test/audits/bootup-time-test.js b/lighthouse-core/test/audits/bootup-time-test.js index 27989c9cafbe..cbe69a8930b6 100644 --- a/lighthouse-core/test/audits/bootup-time-test.js +++ b/lighthouse-core/test/audits/bootup-time-test.js @@ -21,7 +21,7 @@ const errorTrace = JSON.parse( ); describe('Performance: bootup-time audit', () => { - it('should compute the correct BootupTime values', (done) => { + it('should compute the correct BootupTime values', () => { const artifacts = { traces: { [BootupTime.DEFAULT_PASS]: acceptableTrace, @@ -33,17 +33,21 @@ describe('Performance: bootup-time audit', () => { assert.equal(output.score, true); assert.equal(Math.round(output.rawValue), 176); - const valueOf = name => output.extendedInfo.value[name]; - assert.deepEqual(valueOf('https://www.google-analytics.com/analytics.js'), {'Evaluate Script': 40.1, 'Compile Script': 9.6, 'Recalculate Style': 0.2}); - assert.deepEqual(valueOf('https://pwa.rocks/script.js'), {'Evaluate Script': 31.8, 'Layout': 5.5, 'Compile Script': 1.3}); - assert.deepEqual(valueOf('https://www.googletagmanager.com/gtm.js?id=GTM-Q5SW'), {'Evaluate Script': 25, 'Compile Script': 5.5, 'Recalculate Style': 1.2}); - assert.deepEqual(valueOf('https://www.google-analytics.com/plugins/ua/linkid.js'), {'Evaluate Script': 25.2, 'Compile Script': 1.2}); - assert.deepEqual(valueOf('https://www.google-analytics.com/cx/api.js?experiment=jdCfRmudTmy-0USnJ8xPbw'), {'Compile Script': 3, 'Evaluate Script': 1.2}); - assert.deepEqual(valueOf('https://www.google-analytics.com/cx/api.js?experiment=qvpc5qIfRC2EMnbn6bbN5A'), {'Compile Script': 2.5, 'Evaluate Script': 1}); - assert.deepEqual(valueOf('https://pwa.rocks/'), {'Parse HTML': 14.2, 'Evaluate Script': 6.1, 'Compile Script': 1.2}); - assert.deepEqual(valueOf('https://pwa.rocks/0ff789bf.js'), {'Parse HTML': 0}); - - done(); + const roundedValueOf = name => { + const value = output.extendedInfo.value[name]; + const roundedValue = {}; + Object.keys(value).forEach(key => roundedValue[key] = Math.round(value[key] * 10) / 10); + return roundedValue; + }; + + assert.deepEqual(roundedValueOf('https://www.google-analytics.com/analytics.js'), {'Script Evaluation': 40.1, 'Script Parsing & Compile': 9.6, 'Style & Layout': 0.2}); + assert.deepEqual(roundedValueOf('https://pwa.rocks/script.js'), {'Script Evaluation': 31.8, 'Style & Layout': 5.5, 'Script Parsing & Compile': 1.3}); + assert.deepEqual(roundedValueOf('https://www.googletagmanager.com/gtm.js?id=GTM-Q5SW'), {'Script Evaluation': 25, 'Script Parsing & Compile': 5.5, 'Style & Layout': 1.2}); + assert.deepEqual(roundedValueOf('https://www.google-analytics.com/plugins/ua/linkid.js'), {'Script Evaluation': 25.2, 'Script Parsing & Compile': 1.2}); + assert.deepEqual(roundedValueOf('https://www.google-analytics.com/cx/api.js?experiment=jdCfRmudTmy-0USnJ8xPbw'), {'Script Parsing & Compile': 3, 'Script Evaluation': 1.2}); + assert.deepEqual(roundedValueOf('https://www.google-analytics.com/cx/api.js?experiment=qvpc5qIfRC2EMnbn6bbN5A'), {'Script Parsing & Compile': 2.5, 'Script Evaluation': 1}); + assert.deepEqual(roundedValueOf('https://pwa.rocks/'), {'Parsing DOM': 14.2, 'Script Evaluation': 6.1, 'Script Parsing & Compile': 1.2}); + assert.deepEqual(roundedValueOf('https://pwa.rocks/0ff789bf.js'), {'Parsing DOM': 0}); }); it('should get no data when no events are present', () => {