in src/sdk/lh-trace-processor.ts [668:769]
static processTrace(trace, options) {
const { timeOriginDeterminationMethod = 'auto' } = options || {};
// Parse the trace for our key events and sort them by timestamp. Note: sort
// *must* be stable to keep events correctly nested.
const keyEvents = this.filteredTraceSort(trace.traceEvents, e => {
return (
e.cat.includes('blink.user_timing') ||
e.cat.includes('loading') ||
e.cat.includes('devtools.timeline') ||
e.cat === '__metadata'
);
});
// Find the inspected frame
const mainFrameIds = this.findMainFrameIds(keyEvents);
const frames = keyEvents
.filter(
/** @return {evt is FrameCommittedEvent} */ evt => {
return Boolean(
evt.name === 'FrameCommittedInBrowser' &&
evt.args.data &&
evt.args.data.frame &&
evt.args.data.url
);
}
)
.map(evt => {
return {
id: evt.args.data.frame,
url: evt.args.data.url,
parent: evt.args.data.parent,
};
});
const frameIdToRootFrameId = this.resolveRootFrames(frames);
// Filter to just events matching the main frame ID, just to make sure.
const frameEvents = keyEvents.filter(
e => e.args.frame === mainFrameIds.frameId
);
// Filter to just events matching the main frame ID or any child frame IDs.
// In practice, there should always be FrameCommittedInBrowser events to define the frame tree.
// Unfortunately, many test traces do not include FrameCommittedInBrowser events due to minification.
// This ensures there is always a minimal frame tree and events so those tests don't fail.
let frameTreeEvents = [];
if (frameIdToRootFrameId.has(mainFrameIds.frameId)) {
frameTreeEvents = keyEvents.filter(e => {
return (
e.args.frame &&
frameIdToRootFrameId.get(e.args.frame) === mainFrameIds.frameId
);
});
} else {
log(
'frameTreeEvents may be incomplete, make sure the trace has FrameCommittedInBrowser events'
);
frameIdToRootFrameId.set(mainFrameIds.frameId, mainFrameIds.frameId);
frameTreeEvents = frameEvents;
}
// Compute our time origin to use for all relative timings.
const timeOriginEvt = this.computeTimeOrigin(
{ keyEvents, frameEvents, mainFrameIds },
timeOriginDeterminationMethod
);
// Subset all trace events to just our tab's process (incl threads other than main)
// stable-sort events to keep them correctly nested.
const processEvents = TraceProcessor.filteredTraceSort(
trace.traceEvents,
e => e.pid === mainFrameIds.pid
);
const mainThreadEvents = processEvents.filter(
e => e.tid === mainFrameIds.tid
);
// Ensure our traceEnd reflects all page activity.
const traceEnd = this.computeTraceEnd(trace.traceEvents, timeOriginEvt);
// This could be much more concise with object spread, but the consensus is that explicitness is
// preferred over brevity here.
return {
frames,
mainThreadEvents,
frameEvents,
frameTreeEvents,
processEvents,
mainFrameIds,
timeOriginEvt,
timings: {
timeOrigin: 0,
traceEnd: traceEnd.timing,
},
timestamps: {
timeOrigin: timeOriginEvt.ts,
traceEnd: traceEnd.timestamp,
},
};
}