UNPKG

lighthouse

Version:

Automated auditing, performance metrics, and best practices for the web.

228 lines 9.94 kB
export type CpuProfile = { id: string; pid: number; tid: number; startTime: number; nodes: Required<LH.TraceCpuProfile>["nodes"]; samples: Array<number>; timeDeltas: Array<number>; }; export type ProfilerRange = Required<Required<LH.TraceEvent["args"]>["data"]>["_syntheticProfilerRange"]; export type SynthethicEvent = LH.TraceEvent & { args: { data: { _syntheticProfilerRange: ProfilerRange; }; }; }; export type SynthethicTaskNode = Omit<LH.Artifacts.TaskNode, "event"> & { event: SynthethicEvent; endEvent: SynthethicEvent; }; /** * @fileoverview * * This model converts the `Profile` and `ProfileChunk` mega trace events from the `disabled-by-default-v8.cpu_profiler` * category into B/E-style trace events that main-thread-tasks.js already knows how to parse into a task tree. * * The V8 CPU profiler measures where time is being spent by sampling the stack (See https://www.jetbrains.com/help/profiler/Profiling_Guidelines__Choosing_the_Right_Profiling_Mode.html * for a generic description of the differences between tracing and sampling). * * A `Profile` event is a record of the stack that was being executed at different sample points in time. * It has a structure like this: * * nodes: [function A, function B, function C] * samples: [node with id 2, node with id 1, ...] * timeDeltas: [4125μs since last sample, 121μs since last sample, ...] * * Note that this is subtly different from the protocol-based Crdp.Profiler.Profile type. * * Helpful prior art: * @see https://cs.chromium.org/chromium/src/third_party/devtools-frontend/src/front_end/sdk/CPUProfileDataModel.js?sq=package:chromium&g=0&l=42 * @see https://github.com/v8/v8/blob/99ca333b0efba3236954b823101315aefeac51ab/tools/profile.js * @see https://github.com/jlfwong/speedscope/blob/9ed1eb192cb7e9dac43a5f25bd101af169dc654a/src/import/chrome.ts#L200 */ /** * @typedef CpuProfile * @property {string} id * @property {number} pid * @property {number} tid * @property {number} startTime * @property {Required<LH.TraceCpuProfile>['nodes']} nodes * @property {Array<number>} samples * @property {Array<number>} timeDeltas */ /** @typedef {Required<Required<LH.TraceEvent['args']>['data']>['_syntheticProfilerRange']} ProfilerRange */ /** @typedef {LH.TraceEvent & {args: {data: {_syntheticProfilerRange: ProfilerRange}}}} SynthethicEvent */ /** @typedef {Omit<LH.Artifacts.TaskNode, 'event'> & {event: SynthethicEvent, endEvent: SynthethicEvent}} SynthethicTaskNode */ export class CpuProfileModel { /** * @param {LH.TraceEvent | undefined} event * @return {event is SynthethicEvent} */ static isSyntheticEvent(event: LH.TraceEvent | undefined): event is SynthethicEvent; /** * @param {LH.Artifacts.TaskNode} task * @return {task is SynthethicTaskNode} */ static isSyntheticTask(task: LH.Artifacts.TaskNode): task is SynthethicTaskNode; /** * Finds all the tasks that started or ended (depending on `type`) within the provided time range. * Uses a memory index to remember the place in the array the last invocation left off to avoid * re-traversing the entire array, but note that this index might still be slightly off from the * true start position. * * @param {Array<{startTime: number, endTime: number}>} knownTasks * @param {{type: 'startTime'|'endTime', initialIndex: number, earliestPossibleTimestamp: number, latestPossibleTimestamp: number}} options */ static _getTasksInRange(knownTasks: Array<{ startTime: number; endTime: number; }>, options: { type: "startTime" | "endTime"; initialIndex: number; earliestPossibleTimestamp: number; latestPossibleTimestamp: number; }): { tasks: { startTime: number; endTime: number; }[]; lastIndex: number; }; /** * Given a particular time range and a set of known true tasks, find the correct timestamp to use * for a transition between tasks. * * Because the sampling profiler only provides a *range* of start/stop function boundaries, this * method uses knowledge of a known set of tasks to find the most accurate timestamp for a particular * range. For example, if we know that a function ended between 800ms and 810ms, we can use the * knowledge that a toplevel task ended at 807ms to use 807ms as the correct endtime for this function. * * @param {{syntheticTask: SynthethicTaskNode, eventType: 'start'|'end', allEventsAtTs: {naive: Array<SynthethicEvent>, refined: Array<SynthethicEvent>}, knownTaskStartTimeIndex: number, knownTaskEndTimeIndex: number, knownTasksByStartTime: Array<{startTime: number, endTime: number}>, knownTasksByEndTime: Array<{startTime: number, endTime: number}>}} data * @return {{timestamp: number, lastStartTimeIndex: number, lastEndTimeIndex: number}} */ static _findEffectiveTimestamp(data: { syntheticTask: SynthethicTaskNode; eventType: "start" | "end"; allEventsAtTs: { naive: Array<SynthethicEvent>; refined: Array<SynthethicEvent>; }; knownTaskStartTimeIndex: number; knownTaskEndTimeIndex: number; knownTasksByStartTime: Array<{ startTime: number; endTime: number; }>; knownTasksByEndTime: Array<{ startTime: number; endTime: number; }>; }): { timestamp: number; lastStartTimeIndex: number; lastEndTimeIndex: number; }; /** * Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()` * * @param {CpuProfile} profile * @param {Array<LH.Artifacts.TaskNode>} tasks * @return {Array<LH.TraceEvent>} */ static synthesizeTraceEvents(profile: CpuProfile, tasks: Array<LH.Artifacts.TaskNode>): Array<LH.TraceEvent>; /** * Merges the data of all the `ProfileChunk` trace events into a single CpuProfile object for consumption * by `synthesizeTraceEvents()`. * * @param {Array<LH.TraceEvent>} traceEvents * @return {Array<CpuProfile>} */ static collectProfileEvents(traceEvents: Array<LH.TraceEvent>): Array<CpuProfile>; /** * @param {CpuProfile} profile */ constructor(profile: CpuProfile); _profile: CpuProfile; _nodesById: Map<number, { id: number; callFrame: { functionName: string; url?: string; }; parent?: number; }>; _activeNodeArraysById: Map<number, number[]>; /** * Initialization function to enable O(1) access to nodes by node ID. * @return {Map<number, CpuProfile['nodes'][0]>} */ _createNodeMap(): Map<number, CpuProfile["nodes"][0]>; /** * Initialization function to enable O(1) access to the set of active nodes in the stack by node ID. * @return {Map<number, Array<number>>} */ _createActiveNodeArrays(): Map<number, Array<number>>; /** * Returns all the node IDs in a stack when a specific nodeId is at the top of the stack * (i.e. a stack's node ID and the node ID of all of its parents). * * @param {number} nodeId * @return {Array<number>} */ _getActiveNodeIds(nodeId: number): Array<number>; /** * Generates the necessary B/E-style trace events for a single transition from stack A to stack B * at the given latest timestamp (includes possible range in event.args.data). * * Example: * * latestPossibleTimestamp 1234 * previousNodeIds 1,2,3 * currentNodeIds 1,2,4 * * yields [end 3 at ts 1234, begin 4 at ts 1234] * * @param {number} earliestPossibleTimestamp * @param {number} latestPossibleTimestamp * @param {Array<number>} previousNodeIds * @param {Array<number>} currentNodeIds * @return {Array<SynthethicEvent>} */ _synthesizeTraceEventsForTransition(earliestPossibleTimestamp: number, latestPossibleTimestamp: number, previousNodeIds: Array<number>, currentNodeIds: Array<number>): Array<SynthethicEvent>; /** * Creates the B/E-style trace events using only data from the profile itself. Each B/E event will * include the actual _range_ the timestamp could have been in its metadata that is used for * refinement later. * * @return {Array<SynthethicEvent>} */ _synthesizeNaiveTraceEvents(): Array<SynthethicEvent>; /** * Creates a copy of B/E-style trace events with refined timestamps using knowledge from the * tasks that have definitive timestamps. * * With the sampling profiler we know that a function started/ended _sometime between_ two points, * but not exactly when. Using the information from other tasks gives us more information to be * more precise with timings and allows us to create a valid task tree later on. * * @param {Array<{startTime: number, endTime: number}>} knownTasks * @param {Array<SynthethicTaskNode>} syntheticTasks * @param {Array<SynthethicEvent>} syntheticEvents * @return {Array<SynthethicEvent>} */ _refineTraceEventsWithTasks(knownTasks: Array<{ startTime: number; endTime: number; }>, syntheticTasks: Array<SynthethicTaskNode>, syntheticEvents: Array<SynthethicEvent>): Array<SynthethicEvent>; /** * Creates B/E-style trace events from a CpuProfile object created by `collectProfileEvents()`. * An optional set of tasks can be passed in to refine the start/end times. * * @param {Array<LH.Artifacts.TaskNode>} [knownTaskNodes] * @return {Array<LH.TraceEvent>} */ synthesizeTraceEvents(knownTaskNodes?: Array<LH.Artifacts.TaskNode>): Array<LH.TraceEvent>; } //# sourceMappingURL=cpu-profile-model.d.ts.map