diff --git a/lighthouse-core/audits/estimated-input-latency.js b/lighthouse-core/audits/estimated-input-latency.js index 2223b19dbc34..5328ad5531bb 100644 --- a/lighthouse-core/audits/estimated-input-latency.js +++ b/lighthouse-core/audits/estimated-input-latency.js @@ -51,7 +51,7 @@ class EstimatedInputLatency extends Audit { const startTime = artifacts.Speedline.first; const trace = artifacts.traces[this.DEFAULT_TRACE] && - artifacts.traces[this.DEFAULT_TRACE].traceContents; + artifacts.traces[this.DEFAULT_TRACE].traceEvents; const tracingProcessor = new TracingProcessor(); const model = tracingProcessor.init(trace); const latencyPercentiles = TracingProcessor.getRiskToResponsiveness(model, trace, startTime); diff --git a/lighthouse-core/audits/first-meaningful-paint.js b/lighthouse-core/audits/first-meaningful-paint.js index e486ef673664..3221b3ceefa8 100644 --- a/lighthouse-core/audits/first-meaningful-paint.js +++ b/lighthouse-core/audits/first-meaningful-paint.js @@ -53,7 +53,7 @@ class FirstMeaningfulPaint extends Audit { */ static audit(artifacts) { return new Promise((resolve, reject) => { - const traceContents = artifacts.traces[this.DEFAULT_TRACE].traceContents; + const traceContents = artifacts.traces[this.DEFAULT_TRACE].traceEvents; if (!traceContents || !Array.isArray(traceContents)) { throw new Error(FAILURE_MESSAGE); } diff --git a/lighthouse-core/audits/time-to-interactive.js b/lighthouse-core/audits/time-to-interactive.js index b97d498f8064..5df3d64f32e5 100644 --- a/lighthouse-core/audits/time-to-interactive.js +++ b/lighthouse-core/audits/time-to-interactive.js @@ -68,7 +68,7 @@ class TTIMetric extends Audit { // Process the trace const tracingProcessor = new TracingProcessor(); - const traceContents = artifacts.traces[Audit.DEFAULT_TRACE].traceContents; + const traceContents = artifacts.traces[Audit.DEFAULT_TRACE].traceEvents; const model = tracingProcessor.init(traceContents); const endOfTraceTime = model.bounds.max; diff --git a/lighthouse-core/audits/user-timings.js b/lighthouse-core/audits/user-timings.js index f4c1d17b9105..8d92113d7604 100644 --- a/lighthouse-core/audits/user-timings.js +++ b/lighthouse-core/audits/user-timings.js @@ -130,7 +130,7 @@ class UserTimings extends Audit { return new Promise((resolve, reject) => { const traceContents = artifacts.traces[this.DEFAULT_TRACE] && - artifacts.traces[this.DEFAULT_TRACE].traceContents; + artifacts.traces[this.DEFAULT_TRACE].traceEvents; if (!traceContents || !Array.isArray(traceContents)) { throw new Error(FAILURE_MESSAGE); } diff --git a/lighthouse-core/config/index.js b/lighthouse-core/config/index.js index bd2a1a30fb43..eefeebdce466 100644 --- a/lighthouse-core/config/index.js +++ b/lighthouse-core/config/index.js @@ -28,7 +28,7 @@ const log = require('../lib/log'); // and to change TracingStartedInBrowser events into TracingStartedInPage. // This is done by searching for most occuring threads and basing new events // off of those. -function cleanTrace(traceContents) { +function cleanTrace(traceEvents) { // Keep track of most occuring threads const threads = []; const countsByThread = {}; @@ -55,7 +55,7 @@ function cleanTrace(traceContents) { let name; let counter; - traceContents.forEach((evt, idx) => { + traceEvents.forEach((evt, idx) => { if (evt.name.startsWith('TracingStartedIn')) { traceStartEvents.push(idx); } @@ -90,20 +90,20 @@ function cleanTrace(traceContents) { // Remove all current TracingStartedIn* events, storing // the first events ts. - const ts = traceContents[traceStartEvents[0]] && traceContents[traceStartEvents[0]].ts; + const ts = traceEvents[traceStartEvents[0]] && traceEvents[traceStartEvents[0]].ts; // account for offset after removing items let i = 0; for (let dup of traceStartEvents) { - traceContents.splice(dup - i, 1); + traceEvents.splice(dup - i, 1); i++; } // Add a new TracingStartedInPage event based on most active thread // and using TS of first found TracingStartedIn* event - traceContents.unshift(makeMockEvent(mostActiveFrame, ts)); + traceEvents.unshift(makeMockEvent(mostActiveFrame, ts)); - return traceContents; + return traceEvents; } function filterPasses(passes, audits) { @@ -185,20 +185,26 @@ function expandArtifacts(artifacts, includeSpeedline) { // currently only trace logs and performance logs should be imported if (artifacts.traces) { - let trace; Object.keys(artifacts.traces).forEach(key => { - if (artifacts.traces[key].traceContents) { - log.log('info', 'Normalizng trace contents into expected state...'); - trace = require(artifacts.traces[key].traceContents); - - expandedArtifacts.traces[key].traceContents = cleanTrace(trace.traceEvents || trace); + log.log('info', 'Normalizng trace contents into expected state...'); + let trace = require(artifacts.traces[key]); + // Before Chrome 54.0.2816 (codereview.chromium.org/2161583004), trace was + // an array of trace events. After this point, trace is an object with a + // traceEvents property. Normalize to new format. + if (Array.isArray(trace)) { + trace = { + traceEvents: trace + }; } + cleanTrace(trace.traceEvents); + + expandedArtifacts.traces[key] = trace; }); } if (includeSpeedline) { const speedline = new SpeedlineGatherer(); - speedline.afterPass({}, {traceContents: expandedArtifacts.traces.defaultPass.traceContents}); + speedline.afterPass({}, {traceEvents: expandedArtifacts.traces.defaultPass.traceEvents}); expandedArtifacts.Speedline = speedline.artifact; } diff --git a/lighthouse-core/gather/gather-runner.js b/lighthouse-core/gather/gather-runner.js index 738a3c45a4ea..1c00deddc58f 100644 --- a/lighthouse-core/gather/gather-runner.js +++ b/lighthouse-core/gather/gather-runner.js @@ -118,7 +118,18 @@ class GatherRunner { pass = pass.then(_ => { log.log('status', `Gathering: trace "${traceName}"`); return driver.endTrace().then(traceContents => { - loadData.traces[traceName] = {traceContents}; + // Before Chrome 54.0.2816 (codereview.chromium.org/2161583004), + // traceContents was an array of trace events. After this point, + // traceContents is an object with a traceEvents property. Normalize + // to new format. + if (Array.isArray(traceContents)) { + traceContents = { + traceEvents: traceContents + }; + } + + loadData.traces[traceName] = traceContents; + loadData.traceEvents = traceContents.traceEvents; log.verbose('statusEnd', `Gathering: trace "${traceName}"`); }); }); @@ -140,9 +151,6 @@ class GatherRunner { return chain.then(_ => { const status = `Gathering: ${gatherer.name}`; log.log('status', status); - if (config.trace) { - loadData.traceContents = loadData.traces[traceName].traceContents; - } return Promise.resolve(gatherer.afterPass(options, loadData)).then(ret => { log.verbose('statusEnd', status); return ret; @@ -197,10 +205,9 @@ class GatherRunner { .then(_ => this.pass(runOptions)) .then(_ => this.afterPass(runOptions)) .then(loadData => { - // Need to manually merge traces property before - // merging loadDat into tracingData to avoid data loss. - Object.assign(loadData.traces, tracingData.traces); - Object.assign(tracingData, loadData); + // Merge pass trace and network data into tracingData. + Object.assign(tracingData.traces, loadData.traces); + tracingData.networkRecords = loadData.networkRecords; }) .then(_ => this.tearDown(runOptions)); }, Promise.resolve()); diff --git a/lighthouse-core/gather/gatherers/screenshots.js b/lighthouse-core/gather/gatherers/screenshots.js index 8e85e4504177..8e789a32fbd4 100644 --- a/lighthouse-core/gather/gatherers/screenshots.js +++ b/lighthouse-core/gather/gatherers/screenshots.js @@ -46,7 +46,7 @@ class ScreenshotFilmstrip extends Gatherer { } afterPass(options, tracingData) { - return this.getScreenshots(tracingData.traceContents).then(screenshots => { + return this.getScreenshots(tracingData.traceEvents).then(screenshots => { this.artifact = screenshots; }); } diff --git a/lighthouse-core/gather/gatherers/speedline.js b/lighthouse-core/gather/gatherers/speedline.js index 1f548e165448..dcada4cd302b 100644 --- a/lighthouse-core/gather/gatherers/speedline.js +++ b/lighthouse-core/gather/gatherers/speedline.js @@ -22,7 +22,7 @@ const speedline = require('speedline'); class Speedline extends Gatherer { afterPass(options, tracingData) { - return speedline(tracingData.traceContents).then(results => { + return speedline(tracingData.traceEvents).then(results => { this.artifact = results; }).catch(err => { this.artifact = { diff --git a/lighthouse-core/lib/asset-saver.js b/lighthouse-core/lib/asset-saver.js index 246f89015c7e..6501ed50e4de 100644 --- a/lighthouse-core/lib/asset-saver.js +++ b/lighthouse-core/lib/asset-saver.js @@ -81,7 +81,11 @@ function saveArtifacts(artifacts, filename) { } function prepareAssets(options, artifacts) { - const traceData = filterForSize(artifacts.traceContents); + const traceData = Object.keys(artifacts.traces).map(traceName => { + const filteredTrace = Object.assign({}, artifacts.traces[traceName]); + filteredTrace.traceEvents = filterForSize(filteredTrace.traceEvents); + return filteredTrace; + }); const html = screenshotDump(options, artifacts.ScreenshotFilmstrip); return {traceData, html}; } diff --git a/lighthouse-core/test/audits/estimated-input-latency.js b/lighthouse-core/test/audits/estimated-input-latency.js index 9d87a40b2d7e..57f727cd2131 100644 --- a/lighthouse-core/test/audits/estimated-input-latency.js +++ b/lighthouse-core/test/audits/estimated-input-latency.js @@ -17,14 +17,14 @@ const Audit = require('../../audits/estimated-input-latency.js'); const assert = require('assert'); -const traceContents = require('../fixtures/traces/progressive-app.json'); +const traceEvents = require('../fixtures/traces/progressive-app.json'); /* eslint-env mocha */ describe('Performance: estimated-input-latency audit', () => { it('scores a -1 with invalid trace data', () => { const output = Audit.audit({ - traces: {[Audit.DEFAULT_TRACE]: {traceContents: '[{"pid": 15256,"tid": 1295,"t'}}, + traces: {[Audit.DEFAULT_TRACE]: {traceEvents: '[{"pid": 15256,"tid": 1295,"t'}}, Speedline: { first: 500 } @@ -35,7 +35,7 @@ describe('Performance: estimated-input-latency audit', () => { it('evaluates valid input correctly', () => { const output = Audit.audit({ - traces: {[Audit.DEFAULT_TRACE]: {traceContents}}, + traces: {[Audit.DEFAULT_TRACE]: {traceEvents}}, Speedline: { first: 500 } diff --git a/lighthouse-core/test/audits/first-meaningful-paint.js b/lighthouse-core/test/audits/first-meaningful-paint.js index 2332b7320402..76410edfe64f 100644 --- a/lighthouse-core/test/audits/first-meaningful-paint.js +++ b/lighthouse-core/test/audits/first-meaningful-paint.js @@ -17,6 +17,7 @@ const Audit = require('../../audits/first-meaningful-paint.js'); const assert = require('assert'); +const traceEvents = require('../fixtures/traces/progressive-app.json'); /* eslint-env mocha */ describe('Performance: first-meaningful-paint audit', () => { @@ -36,9 +37,8 @@ describe('Performance: first-meaningful-paint audit', () => { let fmpResult; it('processes a valid trace file', done => { - const traceData = require('../fixtures/traces/progressive-app.json'); assert.doesNotThrow(_ => { - Audit.audit({traces: {[Audit.DEFAULT_TRACE]: {traceContents: traceData}}}) + Audit.audit({traces: {[Audit.DEFAULT_TRACE]: {traceEvents}}}) .then(response => { fmpResult = response; done(); diff --git a/lighthouse-core/test/audits/time-to-interactive.js b/lighthouse-core/test/audits/time-to-interactive.js index f6f8a70911d3..b8677ffbbba3 100644 --- a/lighthouse-core/test/audits/time-to-interactive.js +++ b/lighthouse-core/test/audits/time-to-interactive.js @@ -19,7 +19,7 @@ const Audit = require('../../audits/time-to-interactive.js'); const SpeedlineGather = require('../../gather/gatherers/speedline'); const assert = require('assert'); -const traceContents = require('../fixtures/traces/progressive-app.json'); +const traceEvents = require('../fixtures/traces/progressive-app.json'); const speedlineGather = new SpeedlineGather(); /* eslint-env mocha */ @@ -28,7 +28,7 @@ describe('Performance: time-to-interactive audit', () => { return Audit.audit({ traces: { [Audit.DEFAULT_TRACE]: { - traceContents: '[{"pid": 15256,"tid": 1295,"t' + traceEvents: '[{"pid": 15256,"tid": 1295,"t' } }, Speedline: { @@ -41,12 +41,12 @@ describe('Performance: time-to-interactive audit', () => { }); it('evaluates valid input correctly', () => { - let artifacts = {traceContents}; + let artifacts = {traceEvents}; return speedlineGather.afterPass({}, artifacts).then(_ => { artifacts.Speedline = speedlineGather.artifact; // This is usually done by the driver artifacts.traces = { - [Audit.DEFAULT_TRACE]: {traceContents} + [Audit.DEFAULT_TRACE]: {traceEvents} }; return Audit.audit(artifacts).then(output => { assert.equal(output.rawValue, '1105.8'); diff --git a/lighthouse-core/test/audits/user-timing.js b/lighthouse-core/test/audits/user-timing.js index 29f2fa1f51b6..42b1199c73a3 100644 --- a/lighthouse-core/test/audits/user-timing.js +++ b/lighthouse-core/test/audits/user-timing.js @@ -17,7 +17,7 @@ const Audit = require('../../audits/user-timings.js'); const assert = require('assert'); -const traceContents = require('../fixtures/traces/trace-user-timings.json'); +const traceEvents = require('../fixtures/traces/trace-user-timings.json'); /* eslint-env mocha */ @@ -29,7 +29,7 @@ describe('Performance: user-timings audit', () => { }); it('evaluates valid input correctly', () => { - return Audit.audit({traces: {[Audit.DEFAULT_TRACE]: {traceContents}}}) + return Audit.audit({traces: {[Audit.DEFAULT_TRACE]: {traceEvents}}}) .then(response => { assert.equal(response.score, 2); assert.ok(!Number.isNaN(response.extendedInfo.value[0].startTime)); diff --git a/lighthouse-core/test/config/index.js b/lighthouse-core/test/config/index.js index e447fa04190e..e02f74796866 100644 --- a/lighthouse-core/test/config/index.js +++ b/lighthouse-core/test/config/index.js @@ -131,15 +131,13 @@ describe('Config', () => { const config = new Config({ artifacts: { traces: { - defaultPass: { - traceContents: path.resolve(__dirname, '../fixtures/traces/trace-user-timings.json') - } + defaultPass: path.resolve(__dirname, '../fixtures/traces/trace-user-timings.json') }, performanceLog: path.resolve(__dirname, '../fixtures/perflog.json') } }); const traceUserTimings = require('../fixtures/traces/trace-user-timings.json'); - assert.deepStrictEqual(config.artifacts.traces.defaultPass.traceContents, traceUserTimings); + assert.deepStrictEqual(config.artifacts.traces.defaultPass.traceEvents, traceUserTimings); assert.ok(config.artifacts.CriticalRequestChains); assert.ok(config.artifacts.CriticalRequestChains['93149.1']); assert.ok(config.artifacts.CriticalRequestChains['93149.1'].request); @@ -150,16 +148,14 @@ describe('Config', () => { const config = new Config({ artifacts: { traces: { - defaultPass: { - traceContents: path.resolve(__dirname, - '../fixtures/traces/trace-user-timings-no-tracingstartedinpage.json') - } + defaultPass: path.resolve(__dirname, + '../fixtures/traces/trace-user-timings-no-tracingstartedinpage.json') }, performanceLog: path.resolve(__dirname, '../fixtures/perflog.json') } }); - assert.ok(config.artifacts.traces.defaultPass.traceContents.find( + assert.ok(config.artifacts.traces.defaultPass.traceEvents.find( e => e.name === 'TracingStartedInPage' && e.args.data.page === '0xhad00p')); }); @@ -167,10 +163,8 @@ describe('Config', () => { const config = new Config({ artifacts: { traces: { - defaultPass: { - traceContents: path.resolve(__dirname, - '../fixtures/traces/trace-user-timings-no-tracingstartedinpage.json') - } + defaultPass: path.resolve(__dirname, + '../fixtures/traces/trace-user-timings-no-tracingstartedinpage.json') }, performanceLog: path.resolve(__dirname, '../fixtures/perflog.json') }, @@ -187,10 +181,8 @@ describe('Config', () => { const config = new Config({ artifacts: { traces: { - defaultPass: { - traceContents: path.resolve(__dirname, - '../fixtures/traces/trace-user-timings-no-tracingstartedinpage.json') - } + defaultPass: path.resolve(__dirname, + '../fixtures/traces/trace-user-timings-no-tracingstartedinpage.json') }, performanceLog: path.resolve(__dirname, '../fixtures/perflog.json') }, diff --git a/lighthouse-core/test/gather/gather-runner.js b/lighthouse-core/test/gather/gather-runner.js index 0b57acdb4ced..5944284a04a0 100644 --- a/lighthouse-core/test/gather/gather-runner.js +++ b/lighthouse-core/test/gather/gather-runner.js @@ -160,7 +160,7 @@ describe('GatherRunner', function() { return GatherRunner.afterPass({driver, config}).then(vals => { assert.equal(calledTrace, true); - assert.deepEqual(vals.traces[Audit.DEFAULT_TRACE].traceContents, {x: 1}); + assert.deepEqual(vals.traces[Audit.DEFAULT_TRACE], {x: 1}); }); }); @@ -180,7 +180,7 @@ describe('GatherRunner', function() { }; return GatherRunner.afterPass({driver, config}).then(vals => { - assert.deepEqual(vals.traces.notTheDefaultPass.traceContents, {x: 1}); + assert.deepEqual(vals.traces.notTheDefaultPass, {x: 1}); }); }); diff --git a/lighthouse-core/test/gather/gatherers/screenshots.js b/lighthouse-core/test/gather/gatherers/screenshots.js index e59d6899e244..1747f15c7fe8 100644 --- a/lighthouse-core/test/gather/gatherers/screenshots.js +++ b/lighthouse-core/test/gather/gatherers/screenshots.js @@ -19,15 +19,16 @@ const ScreenshotsGather = require('../../../gather/gatherers/screenshots'); const assert = require('assert'); +const traceEvents = require('../../fixtures/traces/progressive-app.json'); + let screenshotsGather = new ScreenshotsGather(); describe('Screenshot gatherer', () => { it('returns an artifact for a real trace', () => { - const traceData = require('../../fixtures/traces/progressive-app.json'); // Currently this test must rely on knowing the phase hook for the gatherer. // A little unfortunate, but we need a "run scheduler with this gatherer, this mocked driver, // and this trace" test class to do that right - return screenshotsGather.afterPass(undefined, {traceContents: traceData}).then(_ => { + return screenshotsGather.afterPass(undefined, {traceEvents}).then(_ => { assert.ok(Array.isArray(screenshotsGather.artifact)); assert.equal(screenshotsGather.artifact.length, 7); diff --git a/lighthouse-core/test/gather/gatherers/speedline.js b/lighthouse-core/test/gather/gatherers/speedline.js index c674d7ea8ad5..0680727af1be 100644 --- a/lighthouse-core/test/gather/gatherers/speedline.js +++ b/lighthouse-core/test/gather/gatherers/speedline.js @@ -19,12 +19,13 @@ const SpeedlineGather = require('../../../gather/gatherers/speedline.js'); const assert = require('assert'); +const traceEvents = require('../../fixtures/traces/progressive-app.json'); describe('Speedline gatherer', () => { it('returns an error debugString on faulty trace data', done => { const speedlineGather = new SpeedlineGather(); - speedlineGather.afterPass({}, {traceContents: {boo: 'ya'}}).then(_ => { + speedlineGather.afterPass({}, {traceEvents: {boo: 'ya'}}).then(_ => { assert.ok(speedlineGather.artifact.debugString); assert.ok(speedlineGather.artifact.debugString.length); done(); @@ -34,9 +35,8 @@ describe('Speedline gatherer', () => { // TODO(samthor): speedIndex requires trace data with frame data. Include multiple short samples. it('measures the pwa.rocks example with speed index of 831', () => { const speedlineGather = new SpeedlineGather(); - const traceContents = require('../../fixtures/traces/progressive-app.json'); - return speedlineGather.afterPass({}, {traceContents}).then(_ => { + return speedlineGather.afterPass({}, {traceEvents}).then(_ => { const speedline = speedlineGather.artifact; return assert.equal(Math.round(speedline.speedIndex), 831); }); diff --git a/lighthouse-core/test/lib/asset-saver.js b/lighthouse-core/test/lib/asset-saver.js index cfe69e4604e6..22920fa384a6 100644 --- a/lighthouse-core/test/lib/asset-saver.js +++ b/lighthouse-core/test/lib/asset-saver.js @@ -22,13 +22,14 @@ const assert = require('assert'); const fs = require('fs'); const ScreenshotFilmstrip = require('../fixtures/traces/screenshots.json'); -const traceContents = require('../fixtures/traces/progressive-app.json'); +const traceEvents = require('../fixtures/traces/progressive-app.json'); +const Audit = require('../../audits/audit.js'); /* eslint-env mocha */ describe('asset-saver helper', () => { it('generates HTML', () => { const options = {url: 'https://testexample.com'}; - const artifacts = {screenshots: [], traceContents: []}; + const artifacts = {screenshots: [], traces: []}; const output = assetSaver.prepareAssets(options, artifacts); assert.ok(/ { } }; const artifacts = { - traceContents, + traces: { + [Audit.DEFAULT_TRACE]: { + traceEvents + } + }, ScreenshotFilmstrip }; diff --git a/lighthouse-core/test/runner.js b/lighthouse-core/test/runner.js index a29e7030cf49..179fa23cc410 100644 --- a/lighthouse-core/test/runner.js +++ b/lighthouse-core/test/runner.js @@ -88,10 +88,7 @@ describe('Runner', () => { artifacts: { traces: { - [Audit.DEFAULT_TRACE]: { - traceContents: path.join(__dirname, - '/fixtures/traces/trace-user-timings.json') - } + [Audit.DEFAULT_TRACE]: path.join(__dirname, '/fixtures/traces/trace-user-timings.json') } } }, flags.auditWhitelist); diff --git a/readme.md b/readme.md index fd74f41b3ae0..e14e827956ce 100644 --- a/readme.md +++ b/readme.md @@ -66,7 +66,7 @@ You can supply your own run configuration to customize what audits you want deta ## Trace processing -Lighthouse can be used to analyze trace and performance data collected from other tools (like WebPageTest and ChromeDriver). The `traceContents` and `performanceLog` artifact items can be provided using a string for the absolute path on disk. The perf log is captured from the Network domain (a la ChromeDriver's [`enableNetwork` option](https://sites.google.com/a/chromium.org/chromedriver/capabilities#TOC-perfLoggingPrefs-object) and reformatted slightly. As an example, here's a trace-only run that's reporting on user timings and critical request chains: +Lighthouse can be used to analyze trace and performance data collected from other tools (like WebPageTest and ChromeDriver). The `traces` and `performanceLog` artifact items can be provided using a string for the absolute path on disk. The perf log is captured from the Network domain (a la ChromeDriver's [`enableNetwork` option](https://sites.google.com/a/chromium.org/chromedriver/capabilities#TOC-perfLoggingPrefs-object) and reformatted slightly. As an example, here's a trace-only run that's reporting on user timings and critical request chains: ##### `config.json` ```js @@ -78,9 +78,7 @@ Lighthouse can be used to analyze trace and performance data collected from othe "artifacts": { "traces": { - "defaultPass": { - "traceContents": "/User/me/lighthouse/lighthouse-core/test/fixtures/traces/trace-user-timings.json" - } + "defaultPass": "/User/me/lighthouse/lighthouse-core/test/fixtures/traces/trace-user-timings.json" }, "performanceLog": "/User/me/lighthouse/lighthouse-core/test/fixtures/traces/perflog.json" },