UNPKG

@quick-game/cli

Version:

Command line interface for rapid qg development

162 lines 5.86 kB
// Copyright 2022 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import * as Platform from '../../../core/platform/platform.js'; import * as Helpers from '../helpers/helpers.js'; import * as Types from '../types/types.js'; /** * IMPORTANT! * See UserTimings.md in this directory for some handy documentation on * UserTimings and the trace events we parse currently. **/ const syntheticEvents = []; const performanceMeasureEvents = []; const performanceMarkEvents = []; const consoleTimings = []; const timestampEvents = []; let handlerState = 1 /* HandlerState.UNINITIALIZED */; export function reset() { syntheticEvents.length = 0; performanceMeasureEvents.length = 0; performanceMarkEvents.length = 0; consoleTimings.length = 0; timestampEvents.length = 0; handlerState = 2 /* HandlerState.INITIALIZED */; } const resourceTimingNames = [ 'workerStart', 'redirectStart', 'redirectEnd', 'fetchStart', 'domainLookupStart', 'domainLookupEnd', 'connectStart', 'connectEnd', 'secureConnectionStart', 'requestStart', 'responseStart', 'responseEnd', ]; const navTimingNames = [ 'navigationStart', 'unloadEventStart', 'unloadEventEnd', 'redirectStart', 'redirectEnd', 'fetchStart', 'commitNavigationEnd', 'domainLookupStart', 'domainLookupEnd', 'connectStart', 'connectEnd', 'secureConnectionStart', 'requestStart', 'responseStart', 'responseEnd', 'domLoading', 'domInteractive', 'domContentLoadedEventStart', 'domContentLoadedEventEnd', 'domComplete', 'loadEventStart', 'loadEventEnd', ]; export function handleEvent(event) { if (handlerState !== 2 /* HandlerState.INITIALIZED */) { throw new Error('UserTimings handler is not initialized'); } // These are events dispatched under the blink.user_timing category // but that the user didn't add. Filter them out so that they do not // Appear in the timings track (they still appear in the main thread // flame chart). const ignoredNames = [...resourceTimingNames, ...navTimingNames]; if (ignoredNames.includes(event.name)) { return; } if (Types.TraceEvents.isTraceEventPerformanceMeasure(event)) { performanceMeasureEvents.push(event); return; } if (Types.TraceEvents.isTraceEventPerformanceMark(event)) { performanceMarkEvents.push(event); } if (Types.TraceEvents.isTraceEventConsoleTime(event)) { consoleTimings.push(event); } if (Types.TraceEvents.isTraceEventTimeStamp(event)) { timestampEvents.push(event); } } export async function finalize() { if (handlerState !== 2 /* HandlerState.INITIALIZED */) { throw new Error('UserTimings handler is not initialized'); } const matchedEvents = new Map(); for (const event of [...performanceMeasureEvents, ...consoleTimings]) { const id = Helpers.Trace.extractId(event); if (id === undefined) { continue; } // Create a synthetic id to prevent collisions across categories. // Console timings can be dispatched with the same id, so use the // event name as well to generate unique ids. const syntheticId = `${event.cat}:${id}:${event.name}`; const otherEventsWithID = Platform.MapUtilities.getWithDefault(matchedEvents, syntheticId, () => { return { begin: null, end: null }; }); const isStartEvent = event.ph === "b" /* Types.TraceEvents.Phase.ASYNC_NESTABLE_START */; const isEndEvent = event.ph === "e" /* Types.TraceEvents.Phase.ASYNC_NESTABLE_END */; if (isStartEvent) { otherEventsWithID.begin = event; } else if (isEndEvent) { otherEventsWithID.end = event; } } for (const [id, eventsPair] of matchedEvents.entries()) { if (!eventsPair.begin || !eventsPair.end) { // This should never happen, the backend only creates the events once it // has them both, so we should never get into this state. // If we do, something is very wrong, so let's just drop that problematic event. continue; } const event = { cat: eventsPair.end.cat, ph: eventsPair.end.ph, pid: eventsPair.end.pid, tid: eventsPair.end.tid, id, // Both events have the same name, so it doesn't matter which we pick to // use as the description name: eventsPair.begin.name, dur: Types.Timing.MicroSeconds(eventsPair.end.ts - eventsPair.begin.ts), ts: eventsPair.begin.ts, args: { data: { beginEvent: eventsPair.begin, endEvent: eventsPair.end, }, }, }; if (event.dur < 0) { // Avoid any pairs that have created a negative duration; this is bad // trace data and we should just ignore them. continue; } syntheticEvents.push(event); } syntheticEvents.sort((a, b) => a.ts - b.ts); handlerState = 3 /* HandlerState.FINALIZED */; } export function data() { if (handlerState !== 3 /* HandlerState.FINALIZED */) { throw new Error('UserTimings handler is not finalized'); } return { performanceMeasures: syntheticEvents.filter(Types.TraceEvents.isTraceEventPerformanceMeasure), consoleTimings: syntheticEvents.filter(Types.TraceEvents.isTraceEventConsoleTime), performanceMarks: [...performanceMarkEvents], timestampEvents: [...timestampEvents], }; } //# sourceMappingURL=UserTimingsHandler.js.map