-
Notifications
You must be signed in to change notification settings - Fork 9.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve reliability of finding navStart #1895
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,7 +32,6 @@ const ComputedArtifact = require('./computed-artifact'); | |
const log = require('../../lib/log'); | ||
|
||
class TraceOfTab extends ComputedArtifact { | ||
|
||
get name() { | ||
return 'TraceOfTab'; | ||
} | ||
|
@@ -43,30 +42,35 @@ class TraceOfTab extends ComputedArtifact { | |
*/ | ||
compute_(trace) { | ||
// Parse the trace for our key events and sort them by timestamp. | ||
const keyEvents = trace.traceEvents.filter(e => { | ||
return e.cat.includes('blink.user_timing') || e.cat.includes('loading') || | ||
const keyEvents = trace.traceEvents | ||
.filter(e => { | ||
return e.cat.includes('blink.user_timing') || | ||
e.cat.includes('loading') || | ||
e.name === 'TracingStartedInPage'; | ||
}).sort((event0, event1) => event0.ts - event1.ts); | ||
}) | ||
.sort((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'); | ||
// Filter to just events matching the frame ID for sanity | ||
const frameEvents = keyEvents.filter(e => e.args.frame === startedInPageEvt.args.data.page); | ||
|
||
// Our navStart will be the last frame navigation in the trace | ||
const navigationStart = frameEvents.filter(e => e.name === 'navigationStart').pop(); | ||
|
||
// Find our first paint of this frame | ||
const firstPaint = frameEvents.find(e => e.name === 'firstPaint'); | ||
// Our navStart will be the latest one before fP. | ||
const navigationStart = frameEvents.filter(e => | ||
e.name === 'navigationStart' && e.ts < firstPaint.ts).pop(); | ||
const firstPaint = frameEvents.find(e => e.name === 'firstPaint' && e.ts > navigationStart.ts); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. strict There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah. if FP was at the same time, i would have BIG concerns about the trace and i'd need to debug it. because that's definitely not correct. |
||
|
||
// FCP will follow at/after the FP | ||
const firstContentfulPaint = frameEvents.find(e => | ||
e.name === 'firstContentfulPaint' && e.ts >= firstPaint.ts); | ||
const firstContentfulPaint = frameEvents.find( | ||
e => e.name === 'firstContentfulPaint' && e.ts > navigationStart.ts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any significance of dropping the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we were using FP as the reference event before. Honestly this line could been asking for > navStart rather than FP, but it was just all FP for consistency. |
||
); | ||
|
||
// fMP will follow at/after the FP | ||
let firstMeaningfulPaint = frameEvents.find(e => | ||
e.name === 'firstMeaningfulPaint' && e.ts >= firstPaint.ts); | ||
let firstMeaningfulPaint = frameEvents.find( | ||
e => e.name === 'firstMeaningfulPaint' && e.ts > navigationStart.ts | ||
); | ||
|
||
// If there was no firstMeaningfulPaint event found in the trace, the network idle detection | ||
// may have not been triggered before Lighthouse finished tracing. | ||
|
@@ -83,17 +87,19 @@ class TraceOfTab extends ComputedArtifact { | |
} | ||
|
||
// subset all trace events to just our tab's process (incl threads other than main) | ||
const processEvents = trace.traceEvents.filter(e => { | ||
return e.pid === startedInPageEvt.pid; | ||
}).sort((event0, event1) => event0.ts - event1.ts); | ||
const processEvents = trace.traceEvents | ||
.filter(e => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: inline |
||
return e.pid === startedInPageEvt.pid; | ||
}) | ||
.sort((event0, event1) => event0.ts - event1.ts); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this formatting change makes the diff hard to read :P no difference, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. correct |
||
|
||
return { | ||
processEvents, | ||
startedInPageEvt: startedInPageEvt, | ||
navigationStartEvt: navigationStart, | ||
firstPaintEvt: firstPaint, | ||
firstContentfulPaintEvt: firstContentfulPaint, | ||
firstMeaningfulPaintEvt: firstMeaningfulPaint | ||
firstMeaningfulPaintEvt: firstMeaningfulPaint, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :D There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I started using https://github.com/prettier/prettier on demand in this PR. I'm already in love. |
||
}; | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -121,25 +121,15 @@ class Metrics { | |
} | ||
|
||
/** | ||
* Getter for our navigationStart trace event | ||
* Get the full trace event for our navigationStart | ||
* @param {!Array<{ts: number, id: string, name: string}>} metrics | ||
*/ | ||
getNavigationStartEvt() { | ||
if (!this._navigationStartEvt) { | ||
const filteredEvents = this._traceEvents.filter(e => { | ||
return e.name === 'TracingStartedInPage' || e.cat === 'blink.user_timing'; | ||
}); | ||
|
||
const tracingStartedEvt = filteredEvents.filter(e => e.name === 'TracingStartedInPage')[0]; | ||
const navigationStartEvt = filteredEvents.filter(e => { | ||
return e.name === 'navigationStart' && | ||
e.pid === tracingStartedEvt.pid && e.tid === tracingStartedEvt.tid; | ||
})[0]; | ||
this._navigationStartEvt = navigationStartEvt; | ||
} | ||
return this._navigationStartEvt; | ||
identifyNavigationStartEvt(metrics) { | ||
const navStartTs = metrics.find(e => e.id === 'navstart').ts; | ||
this._navigationStartEvt = this._traceEvents | ||
.find(e => e.name === 'navigationStart' && e.ts === navStartTs); | ||
} | ||
|
||
|
||
/** | ||
* Constructs performance.measure trace events, which have start/end events as follows: | ||
* { "pid": 89922,"tid":1295,"ts":77176783452,"ph":"b","cat":"blink.user_timing","name":"innermeasure","args":{},"tts":1257886,"id":"0xe66c67"} | ||
|
@@ -148,19 +138,19 @@ class Metrics { | |
* @param {{ts: number, id: string, name: string}} navStart | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete |
||
* @return {!Array} Pair of trace events (start/end) | ||
*/ | ||
synthesizeEventPair(metric, navStart) { | ||
synthesizeEventPair(metric) { | ||
// We'll masquerade our fake events to look mostly like navigationStart | ||
const eventBase = { | ||
pid: this.getNavigationStartEvt().pid, | ||
tid: this.getNavigationStartEvt().tid, | ||
pid: this._navigationStartEvt.pid, | ||
tid: this._navigationStartEvt.tid, | ||
cat: 'blink.user_timing', | ||
name: metric.name, | ||
args: {}, | ||
// randomized id is same for the pair | ||
id: `0x${((Math.random() * 1000000) | 0).toString(16)}` | ||
}; | ||
const fakeMeasureStartEvent = Object.assign({}, eventBase, { | ||
ts: navStart.ts, | ||
ts: this._navigationStartEvt.ts, | ||
ph: 'b' | ||
}); | ||
const fakeMeasureEndEvent = Object.assign({}, eventBase, { | ||
|
@@ -181,10 +171,9 @@ class Metrics { | |
return []; | ||
} | ||
|
||
// confirm our navStart's correctly match | ||
const navStartEvt = metrics.find(e => e.id === 'navstart'); | ||
if (!navStartEvt || this.getNavigationStartEvt().ts !== navStartEvt.ts) { | ||
log.error('pwmetrics-events', 'Reference navigationStart doesn\'t match fMP\'s navStart'); | ||
this.identifyNavigationStartEvt(metrics); | ||
if (!this._navigationStartEvt) { | ||
log.error('pwmetrics-events', 'Reference navigationStart not found'); | ||
return []; | ||
} | ||
|
||
|
@@ -197,7 +186,7 @@ class Metrics { | |
return; | ||
} | ||
log.verbose('pwmetrics-events', `Sythesizing trace events for ${metric.name}`); | ||
fakeEvents.push(...this.synthesizeEventPair(metric, navStartEvt)); | ||
fakeEvents.push(...this.synthesizeEventPair(metric)); | ||
}); | ||
return fakeEvents; | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we throw here if it's undefined so we get slightly more friendly error?