diff --git a/lighthouse-core/gather/computed/trace-of-tab.js b/lighthouse-core/gather/computed/trace-of-tab.js index 62b6ce86f3e4..b21ba09994a2 100644 --- a/lighthouse-core/gather/computed/trace-of-tab.js +++ b/lighthouse-core/gather/computed/trace-of-tab.js @@ -44,19 +44,39 @@ class TraceOfTab extends ComputedArtifact { const keyEvents = trace.traceEvents .filter(e => { return e.cat.includes('blink.user_timing') || - e.cat.includes('loading') || - e.cat.includes('devtools.timeline') || - e.name === 'TracingStartedInPage'; + e.cat.includes('loading') || + e.cat.includes('devtools.timeline') || + e.cat === '__metadata'; }) // @ts-ignore - stableSort added to Array by WebInspector. .stableSort((event0, event1) => event0.ts - event1.ts); - // The first TracingStartedInPage in the trace is definitely our renderer thread of interest - // Beware: the tracingStartedInPage event can appear slightly after a navigationStart - const startedInPageEvt = keyEvents.find(e => e.name === 'TracingStartedInPage'); + // Find out the inspected page frame. + /** @type {LH.TraceEvent|undefined} */ + let startedInPageEvt; + const startedInBrowserEvt = keyEvents.find(e => e.name === 'TracingStartedInBrowser'); + if (startedInBrowserEvt && startedInBrowserEvt.args.data && + startedInBrowserEvt.args.data.frames) { + const mainFrame = startedInBrowserEvt.args.data.frames.find(frame => !frame.parent); + const pid = mainFrame && mainFrame.processId; + const threadNameEvt = keyEvents.find(e => e.pid === pid && e.ph === 'M' && + e.cat === '__metadata' && e.name === 'thread_name' && e.args.name === 'CrRendererMain'); + startedInPageEvt = mainFrame && threadNameEvt ? + Object.assign({}, startedInBrowserEvt, { + pid, tid: threadNameEvt.tid, name: 'TracingStartedInPage', + args: {data: {page: mainFrame.frame}}}) : + undefined; + } + // Support legacy browser versions that do not emit TracingStartedInBrowser event. + if (!startedInPageEvt) { + // The first TracingStartedInPage in the trace is definitely our renderer thread of interest + // Beware: the tracingStartedInPage event can appear slightly after a navigationStart + startedInPageEvt = keyEvents.find(e => e.name === 'TracingStartedInPage'); + } if (!startedInPageEvt) throw new LHError(LHError.errors.NO_TRACING_STARTED); // @ts-ignore - property chain exists for 'TracingStartedInPage' event. const frameId = startedInPageEvt.args.data.page; + // Filter to just events matching the frame ID for sanity const frameEvents = keyEvents.filter(e => e.args.frame === frameId); @@ -106,12 +126,12 @@ class TraceOfTab extends ComputedArtifact { // stable-sort events to keep them correctly nested. /** @type Array */ const processEvents = trace.traceEvents - .filter(e => e.pid === startedInPageEvt.pid) + .filter(e => e.pid === /** @type {LH.TraceEvent} */ (startedInPageEvt).pid) // @ts-ignore - stableSort added to Array by WebInspector. .stableSort((event0, event1) => event0.ts - event1.ts); const mainThreadEvents = processEvents - .filter(e => e.tid === startedInPageEvt.tid); + .filter(e => e.tid === /** @type {LH.TraceEvent} */ (startedInPageEvt).tid); const traceEnd = trace.traceEvents.reduce((max, evt) => { return max.ts > evt.ts ? max : evt; diff --git a/lighthouse-core/test/fixtures/traces/threeframes-blank_content_more.json b/lighthouse-core/test/fixtures/traces/threeframes-blank_content_more.json index 38dfee3ca248..ab528381c16c 100644 --- a/lighthouse-core/test/fixtures/traces/threeframes-blank_content_more.json +++ b/lighthouse-core/test/fixtures/traces/threeframes-blank_content_more.json @@ -20,7 +20,7 @@ "tid": 1295, "ts": 900000000000, "ph": "X", - "cat": "toplevel", + "cat": "devtools.timeline", "name": "TracingStartedInPage", "args": { "data": { diff --git a/lighthouse-core/test/gather/computed/trace-of-tab-test.js b/lighthouse-core/test/gather/computed/trace-of-tab-test.js index cc0d281db0f1..d401e6aa0d7d 100644 --- a/lighthouse-core/test/gather/computed/trace-of-tab-test.js +++ b/lighthouse-core/test/gather/computed/trace-of-tab-test.js @@ -112,6 +112,55 @@ describe('Trace of Tab computed artifact:', () => { assert.equal(trace.firstMeaningfulPaintEvt, undefined, 'bad fmp'); }); + it('handles traces with TracingStartedInBrowser events', async () => { + const tracingStartedInBrowserTrace = { + 'traceEvents': [{ + 'pid': 69850, + 'tid': 69850, + 'ts': 2193564729582, + 'ph': 'I', + 'cat': 'disabled-by-default-devtools.timeline', + 'name': 'TracingStartedInBrowser', + 'args': {'data': { + 'frameTreeNodeId': 1, + 'frames': [{ + 'frame': 'B192D1F3355A6F961EC8F0B01623C1FB', + 'url': 'http://www.example.com/', + 'name': '', + 'processId': 69920, + }], + }}, + 'tts': 1085165, + 's': 't', + }, { + 'pid': 69920, + 'tid': 1, + 'ts': 2193564790059, + 'ph': 'R', + 'cat': 'blink.user_timing', + 'name': 'navigationStart', + 'args': { + 'frame': 'B192D1F3355A6F961EC8F0B01623C1FB', + 'data': { + 'documentLoaderURL': 'http://www.example.com/', + 'isLoadingMainFrame': true, + }, + }, + 'tts': 141371, + }, { + 'pid': 69920, + 'tid': 1, + 'ts': 0, + 'ph': 'M', + 'cat': '__metadata', + 'name': 'thread_name', + 'args': {'name': 'CrRendererMain'}, + }]}; + const trace = await traceOfTab.compute_(tracingStartedInBrowserTrace); + assert.equal(trace.startedInPageEvt.ts, 2193564729582); + assert.equal(trace.navigationStartEvt.ts, 2193564790059); + }); + it('stably sorts events', async () => { const traceJson = fs.readFileSync(__dirname + '/../../fixtures/traces/tracingstarted-after-navstart.json', 'utf8'); diff --git a/typings/externs.d.ts b/typings/externs.d.ts index 1b6a67dc16b5..e5227a0ab55f 100644 --- a/typings/externs.d.ts +++ b/typings/externs.d.ts @@ -137,6 +137,11 @@ declare global { cat: string; args: { data?: { + frames?: { + frame: string; + parent?: string; + processId?: number; + }[]; page?: string; readyState?: number; requestId?: string; @@ -148,6 +153,7 @@ declare global { url?: string; }; frame?: string; + name?: string; }; pid: number; tid: number;