@paulirish/trace_engine 0.0.53 → 0.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.tmp/tsbuildinfo/analyze-inspector-issues.d.mts +13 -0
- package/.tmp/tsbuildinfo/analyze-inspector-issues.d.mts.map +1 -0
- package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
- package/analyze-inspector-issues.mjs +60 -0
- package/core/common/common.d.ts +1 -0
- package/core/common/common.js +1 -0
- package/core/host/host.d.ts +1 -0
- package/core/host/host.js +1 -0
- package/core/platform/ServerTiming.d.ts +31 -0
- package/core/platform/ServerTiming.js +212 -0
- package/core/platform/ServerTiming.js.map +1 -0
- package/core/root/root.d.ts +1 -0
- package/core/root/root.js +1 -0
- package/core/sdk/sdk.d.ts +1 -0
- package/core/sdk/sdk.js +1 -0
- package/models/issues_manager/CheckFormsIssuesTrigger.d.ts +1 -0
- package/models/issues_manager/CheckFormsIssuesTrigger.js +1 -0
- package/models/issues_manager/ContrastCheckTrigger.d.ts +1 -0
- package/models/issues_manager/ContrastCheckTrigger.js +1 -0
- package/models/issues_manager/DeprecationIssue.d.ts +1 -0
- package/models/issues_manager/DeprecationIssue.js +1 -0
- package/models/issues_manager/IssueResolver.d.ts +1 -0
- package/models/issues_manager/IssueResolver.js +1 -0
- package/models/issues_manager/RelatedIssue.d.ts +1 -0
- package/models/issues_manager/RelatedIssue.js +1 -0
- package/models/issues_manager/SourceFrameIssuesManager.d.ts +1 -0
- package/models/issues_manager/SourceFrameIssuesManager.js +1 -0
- package/models/trace/LanternComputationData.js +2 -2
- package/models/trace/LanternComputationData.js.map +1 -1
- package/models/trace/ModelImpl.js +1 -1
- package/models/trace/ModelImpl.js.map +1 -1
- package/models/trace/extras/Metadata.js +2 -2
- package/models/trace/extras/Metadata.js.map +1 -1
- package/models/trace/extras/ThirdParties.js +1 -1
- package/models/trace/extras/ThirdParties.js.map +1 -1
- package/models/trace/extras/TimelineJSProfile.d.ts +13 -0
- package/models/trace/extras/TimelineJSProfile.js +55 -0
- package/models/trace/extras/TimelineJSProfile.js.map +1 -0
- package/models/trace/extras/TraceFilter.js +2 -2
- package/models/trace/extras/TraceFilter.js.map +1 -1
- package/models/trace/extras/URLForEntry.d.ts +12 -0
- package/models/trace/extras/URLForEntry.js +43 -0
- package/models/trace/extras/URLForEntry.js.map +1 -0
- package/models/trace/extras/extras.d.ts +4 -1
- package/models/trace/extras/extras.js +4 -1
- package/models/trace/handlers/AuctionWorkletsHandler.js +5 -5
- package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
- package/models/trace/handlers/ExtensionTraceDataHandler.js +4 -4
- package/models/trace/handlers/ExtensionTraceDataHandler.js.map +1 -1
- package/models/trace/handlers/FlowsHandler.js +3 -3
- package/models/trace/handlers/FlowsHandler.js.map +1 -1
- package/models/trace/handlers/FramesHandler.js +7 -7
- package/models/trace/handlers/FramesHandler.js.map +1 -1
- package/models/trace/handlers/LargestImagePaintHandler.js +2 -2
- package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
- package/models/trace/handlers/LayoutShiftsHandler.d.ts +1 -1
- package/models/trace/handlers/LayoutShiftsHandler.js +18 -10
- package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
- package/models/trace/handlers/MetaHandler.js +7 -7
- package/models/trace/handlers/MetaHandler.js.map +1 -1
- package/models/trace/handlers/NetworkRequestsHandler.js +3 -3
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
- package/models/trace/handlers/PageLoadMetricsHandler.d.ts +2 -2
- package/models/trace/handlers/PageLoadMetricsHandler.js +54 -25
- package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
- package/models/trace/handlers/RendererHandler.js +1 -1
- package/models/trace/handlers/RendererHandler.js.map +1 -1
- package/models/trace/handlers/ServerTimingsHandler.d.ts +9 -0
- package/models/trace/handlers/ServerTimingsHandler.js +106 -0
- package/models/trace/handlers/ServerTimingsHandler.js.map +1 -0
- package/models/trace/handlers/Threads.d.ts +1 -1
- package/models/trace/handlers/Threads.js +17 -7
- package/models/trace/handlers/Threads.js.map +1 -1
- package/models/trace/handlers/UserInteractionsHandler.js +4 -3
- package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
- package/models/trace/handlers/WarningsHandler.js +2 -2
- package/models/trace/handlers/WarningsHandler.js.map +1 -1
- package/models/trace/helpers/SamplesIntegrator.d.ts +1 -1
- package/models/trace/helpers/SamplesIntegrator.js +19 -12
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
- package/models/trace/helpers/Trace.js +111 -111
- package/models/trace/helpers/Trace.js.map +1 -1
- package/models/trace/insights/CLSCulprits.d.ts +1 -1
- package/models/trace/insights/CLSCulprits.js +43 -22
- package/models/trace/insights/CLSCulprits.js.map +1 -1
- package/models/trace/insights/Common.js +4 -3
- package/models/trace/insights/Common.js.map +1 -1
- package/models/trace/insights/CumulativeLayoutShift.d.ts +57 -0
- package/models/trace/insights/CumulativeLayoutShift.js +335 -0
- package/models/trace/insights/CumulativeLayoutShift.js.map +1 -0
- package/models/trace/insights/DOMSize.js +3 -3
- package/models/trace/insights/DOMSize.js.map +1 -1
- package/models/trace/insights/DocumentLatency.js +2 -2
- package/models/trace/insights/DocumentLatency.js.map +1 -1
- package/models/trace/insights/DuplicatedJavaScript.js +2 -2
- package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
- package/models/trace/insights/FontDisplay.js +2 -2
- package/models/trace/insights/FontDisplay.js.map +1 -1
- package/models/trace/insights/ForcedReflow.js +2 -2
- package/models/trace/insights/ForcedReflow.js.map +1 -1
- package/models/trace/insights/ImageDelivery.js +2 -2
- package/models/trace/insights/ImageDelivery.js.map +1 -1
- package/models/trace/insights/InsightRunners.d.ts +9 -0
- package/models/trace/insights/InsightRunners.js +13 -0
- package/models/trace/insights/InsightRunners.js.map +1 -0
- package/models/trace/insights/InteractionToNextPaint.js +3 -3
- package/models/trace/insights/InteractionToNextPaint.js.map +1 -1
- package/models/trace/insights/LCPDiscovery.js +3 -3
- package/models/trace/insights/LCPDiscovery.js.map +1 -1
- package/models/trace/insights/LCPPhases.js +3 -3
- package/models/trace/insights/LCPPhases.js.map +1 -1
- package/models/trace/insights/LargestContentfulPaint.d.ts +38 -0
- package/models/trace/insights/LargestContentfulPaint.js +113 -0
- package/models/trace/insights/LargestContentfulPaint.js.map +1 -0
- package/models/trace/insights/LegacyJavaScript.js +2 -2
- package/models/trace/insights/LegacyJavaScript.js.map +1 -1
- package/models/trace/insights/ModernHTTP.js +2 -2
- package/models/trace/insights/ModernHTTP.js.map +1 -1
- package/models/trace/insights/NetworkDependencyTree.js +2 -2
- package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
- package/models/trace/insights/RenderBlocking.js +3 -3
- package/models/trace/insights/RenderBlocking.js.map +1 -1
- package/models/trace/insights/SlowCSSSelector.js +2 -2
- package/models/trace/insights/SlowCSSSelector.js.map +1 -1
- package/models/trace/insights/ThirdParties.js +2 -2
- package/models/trace/insights/ThirdParties.js.map +1 -1
- package/models/trace/insights/ThirdPartyWeb.d.ts +13 -0
- package/models/trace/insights/ThirdPartyWeb.js +42 -0
- package/models/trace/insights/ThirdPartyWeb.js.map +1 -0
- package/models/trace/insights/Viewport.js +2 -2
- package/models/trace/insights/Viewport.js.map +1 -1
- package/models/trace/insights/types.d.ts +1 -1
- package/models/trace/insights/types.js +19 -0
- package/models/trace/insights/types.js.map +1 -1
- package/models/trace/root-causes/LayoutShift.d.ts +125 -0
- package/models/trace/root-causes/LayoutShift.js +519 -0
- package/models/trace/root-causes/LayoutShift.js.map +1 -0
- package/models/trace/root-causes/RootCauses.d.ts +15 -0
- package/models/trace/root-causes/RootCauses.js +12 -0
- package/models/trace/root-causes/RootCauses.js.map +1 -0
- package/models/trace/root-causes/bundle-tsconfig.json +1 -0
- package/models/trace/root-causes/devtools_entrypoint-bundle-typescript-tsconfig.json +42 -0
- package/models/trace/root-causes/root-causes-tsconfig.json +55 -0
- package/models/trace/root-causes/root-causes.d.ts +1 -0
- package/models/trace/root-causes/root-causes.js +5 -0
- package/models/trace/root-causes/root-causes.js.map +1 -0
- package/models/trace/types/File.d.ts +3 -3
- package/models/trace/types/File.js +28 -4
- package/models/trace/types/File.js.map +1 -1
- package/models/trace/types/TraceEvents.d.ts +6 -6
- package/models/trace/types/TraceEvents.js +373 -105
- package/models/trace/types/TraceEvents.js.map +1 -1
- package/package.json +1 -1
- package/test/test-trace-engine.mjs +77 -0
- package/third_party/marked/marked.d.ts +1 -0
- package/third_party/marked/marked.js +1 -0
- package/.tmp/tsbuildinfo/models/trace/extras/polyfills.d.ts +0 -4
- package/.tmp/tsbuildinfo/models/trace/extras/polyfills.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserInteractionsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/UserInteractionsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {ScoreClassification} from './PageLoadMetricsHandler.js';\nimport type {HandlerName} from './types.js';\n\n// This handler serves two purposes. It generates a list of events that are\n// used to show user clicks in the timeline. It is also used to gather\n// EventTimings into Interactions, which we use to show interactions and\n// highlight long interactions to the user, along with INP.\n\n// We don't need to know which process / thread these events occurred in,\n// because they are effectively global, so we just track all that we find.\nconst allEvents: Types.Events.EventTimingBeginOrEnd[] = [];\n\nconst beginCommitCompositorFrameEvents: Types.Events.BeginCommitCompositorFrame[] = [];\nconst parseMetaViewportEvents: Types.Events.ParseMetaViewport[] = [];\n\nexport const LONG_INTERACTION_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(200));\n\nconst INP_GOOD_TIMING = LONG_INTERACTION_THRESHOLD;\nconst INP_MEDIUM_TIMING = Helpers.Timing.milliToMicro(Types.Timing.Milli(500));\n\nexport interface UserInteractionsData {\n /** All the user events we found in the trace */\n allEvents: readonly Types.Events.EventTimingBeginOrEnd[];\n /** All the BeginCommitCompositorFrame events we found in the trace */\n beginCommitCompositorFrameEvents: readonly Types.Events.BeginCommitCompositorFrame[];\n /** All the ParseMetaViewport events we found in the trace */\n parseMetaViewportEvents: readonly Types.Events.ParseMetaViewport[];\n /** All the interaction events we found in the trace that had an\n * interactionId and a duration > 0\n **/\n interactionEvents: readonly Types.Events.SyntheticInteractionPair[];\n /** If the user rapidly generates interaction events (think typing into a\n * text box), in the UI we only really want to show the user the longest\n * interaction in that set.\n * For example picture interactions like this:\n * ===[interaction A]==========\n * =[interaction B]======\n * =[interaction C]=\n *\n * These events all end at the same time, and so in this instance we only want\n * to show the first interaction A on the timeline, as that is the longest one\n * and the one the developer should be focusing on. So this array of events is\n * all the interaction events filtered down, removing any nested interactions\n * entirely.\n **/\n interactionEventsWithNoNesting: readonly Types.Events.SyntheticInteractionPair[];\n // The longest duration interaction event. Can be null if the trace has no interaction events.\n longestInteractionEvent: Readonly<Types.Events.SyntheticInteractionPair>|null;\n // All interactions that went over the interaction threshold (200ms, see https://web.dev/inp/)\n interactionsOverThreshold: Readonly<Set<Types.Events.SyntheticInteractionPair>>;\n}\n\nlet longestInteractionEvent: Types.Events.SyntheticInteractionPair|null = null;\n\nconst interactionEvents: Types.Events.SyntheticInteractionPair[] = [];\nconst interactionEventsWithNoNesting: Types.Events.SyntheticInteractionPair[] = [];\nconst eventTimingEndEventsById = new Map<string, Types.Events.EventTimingEnd>();\nconst eventTimingStartEventsForInteractions: Types.Events.EventTimingBegin[] = [];\n\nexport function reset(): void {\n allEvents.length = 0;\n beginCommitCompositorFrameEvents.length = 0;\n parseMetaViewportEvents.length = 0;\n interactionEvents.length = 0;\n eventTimingStartEventsForInteractions.length = 0;\n eventTimingEndEventsById.clear();\n interactionEventsWithNoNesting.length = 0;\n longestInteractionEvent = null;\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (Types.Events.isBeginCommitCompositorFrame(event)) {\n beginCommitCompositorFrameEvents.push(event);\n return;\n }\n\n if (Types.Events.isParseMetaViewport(event)) {\n parseMetaViewportEvents.push(event);\n return;\n }\n\n if (!Types.Events.isEventTiming(event)) {\n return;\n }\n\n if (Types.Events.isEventTimingEnd(event)) {\n // Store the end event; for each start event that is an interaction, we need the matching end event to calculate the duration correctly.\n eventTimingEndEventsById.set(event.id, event);\n }\n\n allEvents.push(event);\n\n // From this point on we want to find events that represent interactions.\n // These events are always start events - those are the ones that contain all\n // the metadata about the interaction.\n if (!event.args.data || !Types.Events.isEventTimingStart(event)) {\n return;\n }\n const {duration, interactionId} = event.args.data;\n // We exclude events for the sake of interactions if:\n // 1. They have no duration.\n // 2. They have no interactionId\n // 3. They have an interactionId of 0: this indicates that it's not an\n // interaction that we care about because it hasn't had its own interactionId\n // set (0 is the default on the backend).\n // See: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/responsiveness_metrics.cc;l=133;drc=40c209a9c365ebb9f16fb99dfe78c7fe768b9594\n\n if (duration < 1 || interactionId === undefined || interactionId === 0) {\n return;\n }\n\n // Store the start event. In the finalize() function we will pair this with\n // its end event and create the synthetic interaction event.\n eventTimingStartEventsForInteractions.push(event);\n}\n\n/**\n * See https://web.dev/better-responsiveness-metric/#interaction-types for the\n * table that defines these sets.\n **/\nconst pointerEventTypes = new Set([\n 'pointerdown',\n 'touchstart',\n 'pointerup',\n 'touchend',\n 'mousedown',\n 'mouseup',\n 'click',\n]);\n\nconst keyboardEventTypes = new Set([\n 'keydown',\n 'keypress',\n 'keyup',\n]);\n\nexport type InteractionCategory = 'KEYBOARD'|'POINTER'|'OTHER';\nexport function categoryOfInteraction(interaction: Types.Events.SyntheticInteractionPair): InteractionCategory {\n if (pointerEventTypes.has(interaction.type)) {\n return 'POINTER';\n }\n if (keyboardEventTypes.has(interaction.type)) {\n return 'KEYBOARD';\n }\n\n return 'OTHER';\n}\n\n/**\n * We define a set of interactions as nested where:\n * 1. Their end times align.\n * 2. The longest interaction's start time is earlier than all other\n * interactions with the same end time.\n * 3. The interactions are of the same category [each interaction is either\n * categorised as keyboard, or pointer.]\n *\n * =============A=[pointerup]=\n * ====B=[pointerdown]=\n * ===C=[pointerdown]==\n * ===D=[pointerup]===\n *\n * In this example, B, C and D are all nested and therefore should not be\n * returned from this function.\n *\n * However, in this example we would only consider B nested (under A) and D\n * nested (under C). A and C both stay because they are of different types.\n * ========A=[keydown]====\n * =======B=[keyup]=====\n * ====C=[pointerdown]=\n * =D=[pointerup]=\n **/\nexport function removeNestedInteractions(interactions: readonly Types.Events.SyntheticInteractionPair[]):\n readonly Types.Events.SyntheticInteractionPair[] {\n /**\n * Because we nest events only that are in the same category, we store the\n * longest event for a given end time by category.\n **/\n const earliestEventForEndTimePerCategory:\n Record<InteractionCategory, Map<Types.Timing.Micro, Types.Events.SyntheticInteractionPair>> = {\n POINTER: new Map(),\n KEYBOARD: new Map(),\n OTHER: new Map(),\n };\n\n function storeEventIfEarliestForCategoryAndEndTime(interaction: Types.Events.SyntheticInteractionPair): void {\n const category = categoryOfInteraction(interaction);\n const earliestEventForEndTime = earliestEventForEndTimePerCategory[category];\n const endTime = Types.Timing.Micro(interaction.ts + interaction.dur);\n\n const earliestCurrentEvent = earliestEventForEndTime.get(endTime);\n if (!earliestCurrentEvent) {\n earliestEventForEndTime.set(endTime, interaction);\n return;\n }\n if (interaction.ts < earliestCurrentEvent.ts) {\n earliestEventForEndTime.set(endTime, interaction);\n } else if (\n interaction.ts === earliestCurrentEvent.ts &&\n interaction.interactionId === earliestCurrentEvent.interactionId) {\n // We have seen in traces that the same interaction can have multiple\n // events (e.g. a 'click' and a 'pointerdown'). Often only one of these\n // events will have an event handler bound to it which caused delay on\n // the main thread, and the others will not. This leads to a situation\n // where if we pick one of the events that had no event handler, its\n // processing duration (processingEnd - processingStart) will be 0, but if we\n // had picked the event that had the slow event handler, we would show\n // correctly the main thread delay due to the event handler.\n // So, if we find events with the same interactionId and the same\n // begin/end times, we pick the one with the largest (processingEnd -\n // processingStart) time in order to make sure we find the event with the\n // worst main thread delay, as that is the one the user should care\n // about.\n const currentProcessingDuration = earliestCurrentEvent.processingEnd - earliestCurrentEvent.processingStart;\n const newProcessingDuration = interaction.processingEnd - interaction.processingStart;\n\n // Use the new interaction if it has a longer processing duration than the existing one.\n if (newProcessingDuration > currentProcessingDuration) {\n earliestEventForEndTime.set(endTime, interaction);\n }\n }\n\n // Maximize the processing duration based on the \"children\" interactions.\n // We pick the earliest start processing duration, and the latest end\n // processing duration to avoid under-reporting.\n if (interaction.processingStart < earliestCurrentEvent.processingStart) {\n earliestCurrentEvent.processingStart = interaction.processingStart;\n writeSyntheticTimespans(earliestCurrentEvent);\n }\n if (interaction.processingEnd > earliestCurrentEvent.processingEnd) {\n earliestCurrentEvent.processingEnd = interaction.processingEnd;\n writeSyntheticTimespans(earliestCurrentEvent);\n }\n }\n\n for (const interaction of interactions) {\n storeEventIfEarliestForCategoryAndEndTime(interaction);\n }\n\n // Combine all the events that we have kept from all the per-category event\n // maps back into an array and sort them by timestamp.\n const keptEvents = Object.values(earliestEventForEndTimePerCategory)\n .flatMap(eventsByEndTime => Array.from(eventsByEndTime.values()));\n keptEvents.sort((eventA, eventB) => {\n return eventA.ts - eventB.ts;\n });\n return keptEvents;\n}\n\nfunction writeSyntheticTimespans(event: Types.Events.SyntheticInteractionPair): void {\n const startEvent = event.args.data.beginEvent;\n const endEvent = event.args.data.endEvent;\n\n event.inputDelay = Types.Timing.Micro(event.processingStart - startEvent.ts);\n event.mainThreadHandling = Types.Timing.Micro(event.processingEnd - event.processingStart);\n event.presentationDelay = Types.Timing.Micro(endEvent.ts - event.processingEnd);\n}\n\nexport async function finalize(): Promise<void> {\n const {navigationsByFrameId} = metaHandlerData();\n\n // For each interaction start event, find the async end event by the ID, and then create the Synthetic Interaction event.\n for (const interactionStartEvent of eventTimingStartEventsForInteractions) {\n const endEvent = eventTimingEndEventsById.get(interactionStartEvent.id);\n if (!endEvent) {\n // If we cannot find an end event, bail and drop this event.\n continue;\n }\n const {type, interactionId, timeStamp, processingStart, processingEnd} = interactionStartEvent.args.data;\n if (!type || !interactionId || !timeStamp || !processingStart || !processingEnd) {\n // A valid interaction event that we care about has to have a type (e.g. pointerdown, keyup).\n // We also need to ensure it has an interactionId and various timings. There are edge cases where these aren't included in the trace event.\n continue;\n }\n\n // In the future we will add microsecond timestamps to the trace events…\n // (See https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/window_performance.cc;l=900-901;drc=b503c262e425eae59ced4a80d59d176ed07152c7 )\n // …but until then we can use the millisecond precision values that are in\n // the trace event. To adjust them to be relative to the event.ts and the\n // trace timestamps, for both processingStart and processingEnd we subtract\n // the event timestamp (NOT event.ts, but the timeStamp millisecond value\n // emitted in args.data), and then add that value to the event.ts. This\n // will give us a processingStart and processingEnd time in microseconds\n // that is relative to event.ts, and can be used when drawing boxes.\n // There is some inaccuracy here as we are converting milliseconds to microseconds, but it is good enough until the backend emits more accurate numbers.\n const processingStartRelativeToTraceTime = Types.Timing.Micro(\n Helpers.Timing.milliToMicro(processingStart) - Helpers.Timing.milliToMicro(timeStamp) +\n interactionStartEvent.ts,\n );\n\n const processingEndRelativeToTraceTime = Types.Timing.Micro(\n (Helpers.Timing.milliToMicro(processingEnd) - Helpers.Timing.milliToMicro(timeStamp)) +\n interactionStartEvent.ts);\n\n // Ultimate frameId fallback only needed for TSC, see comments in the type.\n const frameId = interactionStartEvent.args.frame ?? interactionStartEvent.args.data.frame ?? '';\n const navigation = Helpers.Trace.getNavigationForTraceEvent(interactionStartEvent, frameId, navigationsByFrameId);\n const navigationId = navigation?.args.data?.navigationId;\n const interactionEvent =\n Helpers.SyntheticEvents.SyntheticEventsManager.registerSyntheticEvent<Types.Events.SyntheticInteractionPair>({\n // Use the start event to define the common fields.\n rawSourceEvent: interactionStartEvent,\n cat: interactionStartEvent.cat,\n name: interactionStartEvent.name,\n pid: interactionStartEvent.pid,\n tid: interactionStartEvent.tid,\n ph: interactionStartEvent.ph,\n processingStart: processingStartRelativeToTraceTime,\n processingEnd: processingEndRelativeToTraceTime,\n // These will be set in writeSyntheticTimespans()\n inputDelay: Types.Timing.Micro(-1),\n mainThreadHandling: Types.Timing.Micro(-1),\n presentationDelay: Types.Timing.Micro(-1),\n args: {\n data: {\n beginEvent: interactionStartEvent,\n endEvent,\n frame: frameId,\n navigationId,\n },\n },\n ts: interactionStartEvent.ts,\n dur: Types.Timing.Micro(endEvent.ts - interactionStartEvent.ts),\n type: interactionStartEvent.args.data.type,\n interactionId: interactionStartEvent.args.data.interactionId,\n });\n writeSyntheticTimespans(interactionEvent);\n\n interactionEvents.push(interactionEvent);\n }\n\n interactionEventsWithNoNesting.push(...removeNestedInteractions(interactionEvents));\n\n // Pick the longest interactions from the set that were not nested, as we\n // know those are the set of the largest interactions.\n for (const interactionEvent of interactionEventsWithNoNesting) {\n if (!longestInteractionEvent || longestInteractionEvent.dur < interactionEvent.dur) {\n longestInteractionEvent = interactionEvent;\n }\n }\n}\n\nexport function data(): UserInteractionsData {\n return {\n allEvents,\n beginCommitCompositorFrameEvents,\n parseMetaViewportEvents,\n interactionEvents,\n interactionEventsWithNoNesting,\n longestInteractionEvent,\n interactionsOverThreshold: new Set(interactionEvents.filter(event => {\n return event.dur > LONG_INTERACTION_THRESHOLD;\n })),\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['Meta'];\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/articles/inp#good-score\n */\nexport function scoreClassificationForInteractionToNextPaint(timing: Types.Timing.Micro): ScoreClassification {\n if (timing <= INP_GOOD_TIMING) {\n return ScoreClassification.GOOD;\n }\n\n if (timing <= INP_MEDIUM_TIMING) {\n return ScoreClassification.OK;\n }\n\n return ScoreClassification.BAD;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"UserInteractionsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/UserInteractionsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {data as metaHandlerData} from './MetaHandler.js';\nimport {ScoreClassification} from './PageLoadMetricsHandler.js';\nimport type {HandlerName} from './types.js';\n\n// This handler serves two purposes. It generates a list of events that are\n// used to show user clicks in the timeline. It is also used to gather\n// EventTimings into Interactions, which we use to show interactions and\n// highlight long interactions to the user, along with INP.\n\n// We don't need to know which process / thread these events occurred in,\n// because they are effectively global, so we just track all that we find.\nconst allEvents: Types.Events.EventTimingBeginOrEnd[] = [];\n\nconst beginCommitCompositorFrameEvents: Types.Events.BeginCommitCompositorFrame[] = [];\nconst parseMetaViewportEvents: Types.Events.ParseMetaViewport[] = [];\n\nexport const LONG_INTERACTION_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(200));\n\nconst INP_GOOD_TIMING = LONG_INTERACTION_THRESHOLD;\nconst INP_MEDIUM_TIMING = Helpers.Timing.milliToMicro(Types.Timing.Milli(500));\n\nexport interface UserInteractionsData {\n /** All the user events we found in the trace */\n allEvents: readonly Types.Events.EventTimingBeginOrEnd[];\n /** All the BeginCommitCompositorFrame events we found in the trace */\n beginCommitCompositorFrameEvents: readonly Types.Events.BeginCommitCompositorFrame[];\n /** All the ParseMetaViewport events we found in the trace */\n parseMetaViewportEvents: readonly Types.Events.ParseMetaViewport[];\n /** All the interaction events we found in the trace that had an\n * interactionId and a duration > 0\n **/\n interactionEvents: readonly Types.Events.SyntheticInteractionPair[];\n /** If the user rapidly generates interaction events (think typing into a\n * text box), in the UI we only really want to show the user the longest\n * interaction in that set.\n * For example picture interactions like this:\n * ===[interaction A]==========\n * =[interaction B]======\n * =[interaction C]=\n *\n * These events all end at the same time, and so in this instance we only want\n * to show the first interaction A on the timeline, as that is the longest one\n * and the one the developer should be focusing on. So this array of events is\n * all the interaction events filtered down, removing any nested interactions\n * entirely.\n **/\n interactionEventsWithNoNesting: readonly Types.Events.SyntheticInteractionPair[];\n // The longest duration interaction event. Can be null if the trace has no interaction events.\n longestInteractionEvent: Readonly<Types.Events.SyntheticInteractionPair>|null;\n // All interactions that went over the interaction threshold (200ms, see https://web.dev/inp/)\n interactionsOverThreshold: Readonly<Set<Types.Events.SyntheticInteractionPair>>;\n}\n\nlet longestInteractionEvent: Types.Events.SyntheticInteractionPair|null = null;\n\nconst interactionEvents: Types.Events.SyntheticInteractionPair[] = [];\nconst interactionEventsWithNoNesting: Types.Events.SyntheticInteractionPair[] = [];\nconst eventTimingEndEventsById = new Map<string, Types.Events.EventTimingEnd>();\nconst eventTimingStartEventsForInteractions: Types.Events.EventTimingBegin[] = [];\n\nexport function reset(): void {\n allEvents.length = 0;\n beginCommitCompositorFrameEvents.length = 0;\n parseMetaViewportEvents.length = 0;\n interactionEvents.length = 0;\n eventTimingStartEventsForInteractions.length = 0;\n eventTimingEndEventsById.clear();\n interactionEventsWithNoNesting.length = 0;\n longestInteractionEvent = null;\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (Types.Events.isBeginCommitCompositorFrame(event)) {\n beginCommitCompositorFrameEvents.push(event);\n return;\n }\n\n if (Types.Events.isParseMetaViewport(event)) {\n parseMetaViewportEvents.push(event);\n return;\n }\n\n if (!Types.Events.isEventTiming(event)) {\n return;\n }\n\n if (Types.Events.isEventTimingEnd(event)) {\n // Store the end event; for each start event that is an interaction, we need the matching end event to calculate the duration correctly.\n eventTimingEndEventsById.set(event.id, event);\n }\n\n allEvents.push(event);\n\n // From this point on we want to find events that represent interactions.\n // These events are always start events - those are the ones that contain all\n // the metadata about the interaction.\n if (!event.args.data || !Types.Events.isEventTimingStart(event)) {\n return;\n }\n const {duration, interactionId} = event.args.data;\n // We exclude events for the sake of interactions if:\n // 1. They have no duration.\n // 2. They have no interactionId\n // 3. They have an interactionId of 0: this indicates that it's not an\n // interaction that we care about because it hasn't had its own interactionId\n // set (0 is the default on the backend).\n // See: https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/responsiveness_metrics.cc;l=133;drc=40c209a9c365ebb9f16fb99dfe78c7fe768b9594\n\n if (duration < 1 || interactionId === undefined || interactionId === 0) {\n return;\n }\n\n // Store the start event. In the finalize() function we will pair this with\n // its end event and create the synthetic interaction event.\n eventTimingStartEventsForInteractions.push(event);\n}\n\n/**\n * See https://web.dev/better-responsiveness-metric/#interaction-types for the\n * table that defines these sets.\n **/\nconst pointerEventTypes = new Set([\n 'pointerdown',\n 'touchstart',\n 'pointerup',\n 'touchend',\n 'mousedown',\n 'mouseup',\n 'click',\n]);\n\nconst keyboardEventTypes = new Set([\n 'keydown',\n 'keypress',\n 'keyup',\n]);\n\nexport type InteractionCategory = 'KEYBOARD'|'POINTER'|'OTHER';\nexport function categoryOfInteraction(interaction: Types.Events.SyntheticInteractionPair): InteractionCategory {\n if (pointerEventTypes.has(interaction.type)) {\n return 'POINTER';\n }\n if (keyboardEventTypes.has(interaction.type)) {\n return 'KEYBOARD';\n }\n\n return 'OTHER';\n}\n\n/**\n * We define a set of interactions as nested where:\n * 1. Their end times align.\n * 2. The longest interaction's start time is earlier than all other\n * interactions with the same end time.\n * 3. The interactions are of the same category [each interaction is either\n * categorised as keyboard, or pointer.]\n *\n * =============A=[pointerup]=\n * ====B=[pointerdown]=\n * ===C=[pointerdown]==\n * ===D=[pointerup]===\n *\n * In this example, B, C and D are all nested and therefore should not be\n * returned from this function.\n *\n * However, in this example we would only consider B nested (under A) and D\n * nested (under C). A and C both stay because they are of different types.\n * ========A=[keydown]====\n * =======B=[keyup]=====\n * ====C=[pointerdown]=\n * =D=[pointerup]=\n **/\nexport function removeNestedInteractions(interactions: readonly Types.Events.SyntheticInteractionPair[]):\n readonly Types.Events.SyntheticInteractionPair[] {\n /**\n * Because we nest events only that are in the same category, we store the\n * longest event for a given end time by category.\n **/\n const earliestEventForEndTimePerCategory:\n Record<InteractionCategory, Map<Types.Timing.Micro, Types.Events.SyntheticInteractionPair>> = {\n POINTER: new Map(),\n KEYBOARD: new Map(),\n OTHER: new Map(),\n };\n\n function storeEventIfEarliestForCategoryAndEndTime(interaction: Types.Events.SyntheticInteractionPair): void {\n const category = categoryOfInteraction(interaction);\n const earliestEventForEndTime = earliestEventForEndTimePerCategory[category];\n const endTime = Types.Timing.Micro(interaction.ts + interaction.dur);\n\n const earliestCurrentEvent = earliestEventForEndTime.get(endTime);\n if (!earliestCurrentEvent) {\n earliestEventForEndTime.set(endTime, interaction);\n return;\n }\n if (interaction.ts < earliestCurrentEvent.ts) {\n earliestEventForEndTime.set(endTime, interaction);\n } else if (\n interaction.ts === earliestCurrentEvent.ts &&\n interaction.interactionId === earliestCurrentEvent.interactionId) {\n // We have seen in traces that the same interaction can have multiple\n // events (e.g. a 'click' and a 'pointerdown'). Often only one of these\n // events will have an event handler bound to it which caused delay on\n // the main thread, and the others will not. This leads to a situation\n // where if we pick one of the events that had no event handler, its\n // processing duration (processingEnd - processingStart) will be 0, but if we\n // had picked the event that had the slow event handler, we would show\n // correctly the main thread delay due to the event handler.\n // So, if we find events with the same interactionId and the same\n // begin/end times, we pick the one with the largest (processingEnd -\n // processingStart) time in order to make sure we find the event with the\n // worst main thread delay, as that is the one the user should care\n // about.\n const currentProcessingDuration = earliestCurrentEvent.processingEnd - earliestCurrentEvent.processingStart;\n const newProcessingDuration = interaction.processingEnd - interaction.processingStart;\n\n // Use the new interaction if it has a longer processing duration than the existing one.\n if (newProcessingDuration > currentProcessingDuration) {\n earliestEventForEndTime.set(endTime, interaction);\n }\n }\n\n // Maximize the processing duration based on the \"children\" interactions.\n // We pick the earliest start processing duration, and the latest end\n // processing duration to avoid under-reporting.\n if (interaction.processingStart < earliestCurrentEvent.processingStart) {\n earliestCurrentEvent.processingStart = interaction.processingStart;\n writeSyntheticTimespans(earliestCurrentEvent);\n }\n if (interaction.processingEnd > earliestCurrentEvent.processingEnd) {\n earliestCurrentEvent.processingEnd = interaction.processingEnd;\n writeSyntheticTimespans(earliestCurrentEvent);\n }\n }\n\n for (const interaction of interactions) {\n storeEventIfEarliestForCategoryAndEndTime(interaction);\n }\n\n // Combine all the events that we have kept from all the per-category event\n // maps back into an array and sort them by timestamp.\n const keptEvents = Object.values(earliestEventForEndTimePerCategory)\n .flatMap(eventsByEndTime => Array.from(eventsByEndTime.values()));\n keptEvents.sort((eventA, eventB) => {\n return eventA.ts - eventB.ts;\n });\n return keptEvents;\n}\n\nfunction writeSyntheticTimespans(event: Types.Events.SyntheticInteractionPair): void {\n const startEvent = event.args.data.beginEvent;\n const endEvent = event.args.data.endEvent;\n\n event.inputDelay = Types.Timing.Micro(event.processingStart - startEvent.ts);\n event.mainThreadHandling = Types.Timing.Micro(event.processingEnd - event.processingStart);\n event.presentationDelay = Types.Timing.Micro(endEvent.ts - event.processingEnd);\n}\n\nexport async function finalize(): Promise<void> {\n const {navigationsByFrameId} = metaHandlerData();\n\n // For each interaction start event, find the async end event by the ID, and then create the Synthetic Interaction event.\n for (const interactionStartEvent of eventTimingStartEventsForInteractions) {\n const endEvent = eventTimingEndEventsById.get(interactionStartEvent.id);\n if (!endEvent) {\n // If we cannot find an end event, bail and drop this event.\n continue;\n }\n const {type, interactionId, timeStamp, processingStart, processingEnd} = interactionStartEvent.args.data;\n if (!type || !interactionId || !timeStamp || !processingStart || !processingEnd) {\n // A valid interaction event that we care about has to have a type (e.g. pointerdown, keyup).\n // We also need to ensure it has an interactionId and various timings. There are edge cases where these aren't included in the trace event.\n continue;\n }\n\n // In the future we will add microsecond timestamps to the trace events…\n // (See https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/timing/window_performance.cc;l=900-901;drc=b503c262e425eae59ced4a80d59d176ed07152c7 )\n // …but until then we can use the millisecond precision values that are in\n // the trace event. To adjust them to be relative to the event.ts and the\n // trace timestamps, for both processingStart and processingEnd we subtract\n // the event timestamp (NOT event.ts, but the timeStamp millisecond value\n // emitted in args.data), and then add that value to the event.ts. This\n // will give us a processingStart and processingEnd time in microseconds\n // that is relative to event.ts, and can be used when drawing boxes.\n // There is some inaccuracy here as we are converting milliseconds to microseconds, but it is good enough until the backend emits more accurate numbers.\n const processingStartRelativeToTraceTime = Types.Timing.Micro(\n Helpers.Timing.milliToMicro(processingStart) - Helpers.Timing.milliToMicro(timeStamp) +\n interactionStartEvent.ts,\n );\n\n const processingEndRelativeToTraceTime = Types.Timing.Micro(\n (Helpers.Timing.milliToMicro(processingEnd) - Helpers.Timing.milliToMicro(timeStamp)) +\n interactionStartEvent.ts);\n\n // Ultimate frameId fallback only needed for TSC, see comments in the type.\n const frameId = interactionStartEvent.args.frame ?? interactionStartEvent.args.data.frame ?? '';\n const navigation = Helpers.Trace.getNavigationForTraceEvent(interactionStartEvent, frameId, navigationsByFrameId);\n const navigationId = navigation?.args.data?.navigationId;\n const interactionEvent =\n Helpers.SyntheticEvents.SyntheticEventsManager.registerSyntheticEvent<Types.Events.SyntheticInteractionPair>({\n // Use the start event to define the common fields.\n rawSourceEvent: interactionStartEvent,\n cat: interactionStartEvent.cat,\n name: interactionStartEvent.name,\n pid: interactionStartEvent.pid,\n tid: interactionStartEvent.tid,\n ph: interactionStartEvent.ph,\n processingStart: processingStartRelativeToTraceTime,\n processingEnd: processingEndRelativeToTraceTime,\n // These will be set in writeSyntheticTimespans()\n inputDelay: Types.Timing.Micro(-1),\n mainThreadHandling: Types.Timing.Micro(-1),\n presentationDelay: Types.Timing.Micro(-1),\n args: {\n data: {\n beginEvent: interactionStartEvent,\n endEvent,\n frame: frameId,\n navigationId,\n },\n },\n ts: interactionStartEvent.ts,\n dur: Types.Timing.Micro(endEvent.ts - interactionStartEvent.ts),\n type: interactionStartEvent.args.data.type,\n interactionId: interactionStartEvent.args.data.interactionId,\n });\n writeSyntheticTimespans(interactionEvent);\n\n interactionEvents.push(interactionEvent);\n }\n\n interactionEventsWithNoNesting.push(...removeNestedInteractions(interactionEvents));\n\n // Pick the longest interactions from the set that were not nested, as we\n // know those are the set of the largest interactions.\n for (const interactionEvent of interactionEventsWithNoNesting) {\n if (!longestInteractionEvent || longestInteractionEvent.dur < interactionEvent.dur) {\n longestInteractionEvent = interactionEvent;\n }\n }\n}\n\nexport function data(): UserInteractionsData {\n return {\n allEvents,\n beginCommitCompositorFrameEvents,\n parseMetaViewportEvents,\n interactionEvents,\n interactionEventsWithNoNesting,\n longestInteractionEvent,\n interactionsOverThreshold: new Set(interactionEvents.filter(event => {\n return event.dur > LONG_INTERACTION_THRESHOLD;\n })),\n };\n}\n\nexport function deps(): HandlerName[] {\n return ['Meta'];\n}\n\n/**\n * Classifications sourced from\n * https://web.dev/articles/inp#good-score\n */\nexport function scoreClassificationForInteractionToNextPaint(timing: Types.Timing.Micro): ScoreClassification {\n if (timing <= INP_GOOD_TIMING) {\n return ScoreClassification.GOOD;\n }\n\n if (timing <= INP_MEDIUM_TIMING) {\n return ScoreClassification.OK;\n }\n\n return ScoreClassification.BAD;\n}\n"]}
|
|
@@ -46,7 +46,7 @@ function storeWarning(event, warning) {
|
|
|
46
46
|
}
|
|
47
47
|
export function handleEvent(event) {
|
|
48
48
|
processForcedReflowWarning(event);
|
|
49
|
-
if (event.name ===
|
|
49
|
+
if (event.name === Types.Events.Name.RUN_TASK) {
|
|
50
50
|
const { duration } = Helpers.Timing.eventTimingsMicroSeconds(event);
|
|
51
51
|
if (duration > LONG_MAIN_THREAD_TASK_THRESHOLD) {
|
|
52
52
|
longTaskEvents.push(event);
|
|
@@ -74,7 +74,7 @@ function processForcedReflowWarning(event) {
|
|
|
74
74
|
accomodateEventInStack(event, jsInvokeStack, /* pushEventToStack */ Types.Events.isJSInvocationEvent(event));
|
|
75
75
|
if (jsInvokeStack.length) {
|
|
76
76
|
// Current event falls inside a JS call.
|
|
77
|
-
if (event.name ===
|
|
77
|
+
if (event.name === Types.Events.Name.LAYOUT || event.name === Types.Events.Name.UPDATE_LAYOUT_TREE) {
|
|
78
78
|
// A forced reflow happened. However we need to check if
|
|
79
79
|
// the threshold is surpassed to add a warning. Accumulate the
|
|
80
80
|
// event to check for this after the current Task is over.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WarningsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/WarningsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport type {HandlerName} from './types.js';\nimport {data as userInteractionsHandlerData} from './UserInteractionsHandler.js';\nimport {data as workersData} from './WorkersHandler.js';\n\nexport interface WarningsData {\n // Tracks warnings keyed by the event.\n perEvent: Map<Types.Events.Event, Warning[]>;\n // The same data in reverse: for each type of warning, track the events.\n // Useful if we need to enumerate events by type of issue\n perWarning: Map<Warning, Types.Events.Event[]>;\n}\n\nexport type Warning = 'LONG_TASK'|'IDLE_CALLBACK_OVER_TIME'|'FORCED_REFLOW'|'LONG_INTERACTION';\n\nconst warningsPerEvent: WarningsData['perEvent'] = new Map();\nconst eventsPerWarning: WarningsData['perWarning'] = new Map();\n\n/**\n * Tracks the stack formed by nested trace events up to a given point\n */\nconst allEventsStack: Types.Events.Event[] = [];\n/**\n * Tracks the stack formed by JS invocation trace events up to a given point.\n * F.e. FunctionCall, EvaluateScript, V8Execute.\n * Not to be confused with ProfileCalls.\n */\nconst jsInvokeStack: Types.Events.Event[] = [];\n/**\n * Tracks reflow events in a task.\n */\nconst taskReflowEvents: Types.Events.Event[] = [];\n/**\n * Tracks events containing long running tasks. These are compared later against the worker thread pool to filter out long tasks from worker threads.\n */\nconst longTaskEvents: Types.Events.Event[] = [];\n\nexport const FORCED_REFLOW_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(30));\n\nexport const LONG_MAIN_THREAD_TASK_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(50));\n\nexport function reset(): void {\n warningsPerEvent.clear();\n eventsPerWarning.clear();\n allEventsStack.length = 0;\n jsInvokeStack.length = 0;\n taskReflowEvents.length = 0;\n longTaskEvents.length = 0;\n}\n\nfunction storeWarning(event: Types.Events.Event, warning: Warning): void {\n const existingWarnings = Platform.MapUtilities.getWithDefault(warningsPerEvent, event, () => []);\n existingWarnings.push(warning);\n warningsPerEvent.set(event, existingWarnings);\n\n const existingEvents = Platform.MapUtilities.getWithDefault(eventsPerWarning, warning, () => []);\n existingEvents.push(event);\n eventsPerWarning.set(warning, existingEvents);\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n processForcedReflowWarning(event);\n if (event.name === Types.Events.Name.RUN_TASK) {\n const {duration} = Helpers.Timing.eventTimingsMicroSeconds(event);\n if (duration > LONG_MAIN_THREAD_TASK_THRESHOLD) {\n longTaskEvents.push(event);\n }\n return;\n }\n\n if (Types.Events.isFireIdleCallback(event)) {\n const {duration} = Helpers.Timing.eventTimingsMilliSeconds(event);\n if (duration > event.args.data.allottedMilliseconds) {\n storeWarning(event, 'IDLE_CALLBACK_OVER_TIME');\n }\n return;\n }\n}\n\n/**\n * Reflows* are added a warning to if:\n * 1. They are forced/sync, meaning they are invoked by JS and finish\n * during the Script execution.\n * 2. Their duration exceeds a threshold.\n * - *Reflow: The style recalculation and layout steps in a render task.\n */\nfunction processForcedReflowWarning(event: Types.Events.Event): void {\n // Update the event and the JS invocation stacks.\n accomodateEventInStack(event, allEventsStack);\n accomodateEventInStack(event, jsInvokeStack, /* pushEventToStack */ Types.Events.isJSInvocationEvent(event));\n if (jsInvokeStack.length) {\n // Current event falls inside a JS call.\n if (event.name === Types.Events.Name.LAYOUT || event.name === Types.Events.Name.UPDATE_LAYOUT_TREE) {\n // A forced reflow happened. However we need to check if\n // the threshold is surpassed to add a warning. Accumulate the\n // event to check for this after the current Task is over.\n taskReflowEvents.push(event);\n return;\n }\n }\n if (allEventsStack.length === 1) {\n // We hit a new task. Check if the forced reflows in the previous\n // task exceeded the threshold and add a warning if so.\n const totalTime = taskReflowEvents.reduce((time, event) => time + (event.dur || 0), 0);\n if (totalTime >= FORCED_REFLOW_THRESHOLD) {\n taskReflowEvents.forEach(reflowEvent => storeWarning(reflowEvent, 'FORCED_REFLOW'));\n }\n taskReflowEvents.length = 0;\n }\n}\n\n/**\n * Updates a given trace event stack given a new event.\n */\nfunction accomodateEventInStack(event: Types.Events.Event, stack: Types.Events.Event[], pushEventToStack = true): void {\n let nextItem = stack.at(-1);\n while (nextItem && event.ts > nextItem.ts + (nextItem.dur || 0)) {\n stack.pop();\n nextItem = stack.at(-1);\n }\n if (!pushEventToStack) {\n return;\n }\n stack.push(event);\n}\n\nexport function deps(): HandlerName[] {\n return ['UserInteractions', 'Workers'];\n}\n\nexport async function finalize(): Promise<void> {\n // These events do exist on the UserInteractionsHandler, but we also put\n // them into the WarningsHandler so that the warnings handler can be the\n // source of truth and the way to look up all warnings for a given event.\n // Otherwise, we would have to look up warnings across multiple handlers for\n // a given event, which will start to get messy very quickly.\n const longInteractions = userInteractionsHandlerData().interactionsOverThreshold;\n for (const interaction of longInteractions) {\n storeWarning(interaction, 'LONG_INTERACTION');\n }\n\n for (const event of longTaskEvents) {\n if (!(event.tid, workersData().workerIdByThread.has(event.tid))) {\n storeWarning(event, 'LONG_TASK');\n }\n }\n longTaskEvents.length = 0;\n}\n\nexport function data(): WarningsData {\n return {\n perEvent: warningsPerEvent,\n perWarning: eventsPerWarning,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"WarningsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/WarningsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Platform from '../../../core/platform/platform.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport type {HandlerName} from './types.js';\nimport {data as userInteractionsHandlerData} from './UserInteractionsHandler.js';\nimport {data as workersData} from './WorkersHandler.js';\n\nexport interface WarningsData {\n // Tracks warnings keyed by the event.\n perEvent: Map<Types.Events.Event, Warning[]>;\n // The same data in reverse: for each type of warning, track the events.\n // Useful if we need to enumerate events by type of issue\n perWarning: Map<Warning, Types.Events.Event[]>;\n}\n\nexport type Warning = 'LONG_TASK'|'IDLE_CALLBACK_OVER_TIME'|'FORCED_REFLOW'|'LONG_INTERACTION';\n\nconst warningsPerEvent: WarningsData['perEvent'] = new Map();\nconst eventsPerWarning: WarningsData['perWarning'] = new Map();\n\n/**\n * Tracks the stack formed by nested trace events up to a given point\n */\nconst allEventsStack: Types.Events.Event[] = [];\n/**\n * Tracks the stack formed by JS invocation trace events up to a given point.\n * F.e. FunctionCall, EvaluateScript, V8Execute.\n * Not to be confused with ProfileCalls.\n */\nconst jsInvokeStack: Types.Events.Event[] = [];\n/**\n * Tracks reflow events in a task.\n */\nconst taskReflowEvents: Types.Events.Event[] = [];\n/**\n * Tracks events containing long running tasks. These are compared later against the worker thread pool to filter out long tasks from worker threads.\n */\nconst longTaskEvents: Types.Events.Event[] = [];\n\nexport const FORCED_REFLOW_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(30));\n\nexport const LONG_MAIN_THREAD_TASK_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(50));\n\nexport function reset(): void {\n warningsPerEvent.clear();\n eventsPerWarning.clear();\n allEventsStack.length = 0;\n jsInvokeStack.length = 0;\n taskReflowEvents.length = 0;\n longTaskEvents.length = 0;\n}\n\nfunction storeWarning(event: Types.Events.Event, warning: Warning): void {\n const existingWarnings = Platform.MapUtilities.getWithDefault(warningsPerEvent, event, () => []);\n existingWarnings.push(warning);\n warningsPerEvent.set(event, existingWarnings);\n\n const existingEvents = Platform.MapUtilities.getWithDefault(eventsPerWarning, warning, () => []);\n existingEvents.push(event);\n eventsPerWarning.set(warning, existingEvents);\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n processForcedReflowWarning(event);\n if (event.name === Types.Events.Name.RUN_TASK) {\n const {duration} = Helpers.Timing.eventTimingsMicroSeconds(event);\n if (duration > LONG_MAIN_THREAD_TASK_THRESHOLD) {\n longTaskEvents.push(event);\n }\n return;\n }\n\n if (Types.Events.isFireIdleCallback(event)) {\n const {duration} = Helpers.Timing.eventTimingsMilliSeconds(event);\n if (duration > event.args.data.allottedMilliseconds) {\n storeWarning(event, 'IDLE_CALLBACK_OVER_TIME');\n }\n return;\n }\n}\n\n/**\n * Reflows* are added a warning to if:\n * 1. They are forced/sync, meaning they are invoked by JS and finish\n * during the Script execution.\n * 2. Their duration exceeds a threshold.\n * - *Reflow: The style recalculation and layout steps in a render task.\n */\nfunction processForcedReflowWarning(event: Types.Events.Event): void {\n // Update the event and the JS invocation stacks.\n accomodateEventInStack(event, allEventsStack);\n accomodateEventInStack(event, jsInvokeStack, /* pushEventToStack */ Types.Events.isJSInvocationEvent(event));\n if (jsInvokeStack.length) {\n // Current event falls inside a JS call.\n if (event.name === Types.Events.Name.LAYOUT || event.name === Types.Events.Name.UPDATE_LAYOUT_TREE) {\n // A forced reflow happened. However we need to check if\n // the threshold is surpassed to add a warning. Accumulate the\n // event to check for this after the current Task is over.\n taskReflowEvents.push(event);\n return;\n }\n }\n if (allEventsStack.length === 1) {\n // We hit a new task. Check if the forced reflows in the previous\n // task exceeded the threshold and add a warning if so.\n const totalTime = taskReflowEvents.reduce((time, event) => time + (event.dur || 0), 0);\n if (totalTime >= FORCED_REFLOW_THRESHOLD) {\n taskReflowEvents.forEach(reflowEvent => storeWarning(reflowEvent, 'FORCED_REFLOW'));\n }\n taskReflowEvents.length = 0;\n }\n}\n\n/**\n * Updates a given trace event stack given a new event.\n */\nfunction accomodateEventInStack(event: Types.Events.Event, stack: Types.Events.Event[], pushEventToStack = true): void {\n let nextItem = stack.at(-1);\n while (nextItem && event.ts > nextItem.ts + (nextItem.dur || 0)) {\n stack.pop();\n nextItem = stack.at(-1);\n }\n if (!pushEventToStack) {\n return;\n }\n stack.push(event);\n}\n\nexport function deps(): HandlerName[] {\n return ['UserInteractions', 'Workers'];\n}\n\nexport async function finalize(): Promise<void> {\n // These events do exist on the UserInteractionsHandler, but we also put\n // them into the WarningsHandler so that the warnings handler can be the\n // source of truth and the way to look up all warnings for a given event.\n // Otherwise, we would have to look up warnings across multiple handlers for\n // a given event, which will start to get messy very quickly.\n const longInteractions = userInteractionsHandlerData().interactionsOverThreshold;\n for (const interaction of longInteractions) {\n storeWarning(interaction, 'LONG_INTERACTION');\n }\n\n for (const event of longTaskEvents) {\n if (!(event.tid, workersData().workerIdByThread.has(event.tid))) {\n storeWarning(event, 'LONG_TASK');\n }\n }\n longTaskEvents.length = 0;\n}\n\nexport function data(): WarningsData {\n return {\n perEvent: warningsPerEvent,\n perWarning: eventsPerWarning,\n };\n}\n"]}
|
|
@@ -54,7 +54,7 @@ export declare class SamplesIntegrator {
|
|
|
54
54
|
static createFakeTraceFromCpuProfile(profile: Protocol.Profiler.Profile, tid: Types.Events.ThreadID): Types.File.TraceFile;
|
|
55
55
|
}
|
|
56
56
|
export declare namespace SamplesIntegrator {
|
|
57
|
-
|
|
57
|
+
enum NativeGroups {
|
|
58
58
|
COMPILE = "Compile",
|
|
59
59
|
PARSE = "Parse"
|
|
60
60
|
}
|
|
@@ -109,7 +109,7 @@ export class SamplesIntegrator {
|
|
|
109
109
|
// Because instant trace events have no duration, they don't provide
|
|
110
110
|
// useful information for possible changes in the duration of calls
|
|
111
111
|
// in the JS stack.
|
|
112
|
-
if (event.ph ===
|
|
112
|
+
if (event.ph === Types.Events.Phase.INSTANT && !extractSampleTraceId(event)) {
|
|
113
113
|
continue;
|
|
114
114
|
}
|
|
115
115
|
if (stack.length === 0) {
|
|
@@ -155,7 +155,7 @@ export class SamplesIntegrator {
|
|
|
155
155
|
#onTraceEventStart(event) {
|
|
156
156
|
// Top level events cannot be nested into JS frames so we reset
|
|
157
157
|
// the stack when we find one.
|
|
158
|
-
if (event.name ===
|
|
158
|
+
if (event.name === Types.Events.Name.RUN_MICROTASKS || event.name === Types.Events.Name.RUN_TASK) {
|
|
159
159
|
this.#lockedJsStackDepth = [];
|
|
160
160
|
this.#truncateJSStack(0, event.ts);
|
|
161
161
|
this.#fakeJSInvocation = false;
|
|
@@ -400,12 +400,12 @@ export class SamplesIntegrator {
|
|
|
400
400
|
}
|
|
401
401
|
#makeJSSampleEvent(call, timestamp, traceId) {
|
|
402
402
|
const JSSampleEvent = {
|
|
403
|
-
name:
|
|
403
|
+
name: Types.Events.Name.JS_SAMPLE,
|
|
404
404
|
cat: 'devtools.timeline',
|
|
405
405
|
args: {
|
|
406
406
|
data: { traceId, stackTrace: this.#makeProfileCallsForStack(call).map(e => e.callFrame) },
|
|
407
407
|
},
|
|
408
|
-
ph:
|
|
408
|
+
ph: Types.Events.Phase.INSTANT,
|
|
409
409
|
ts: timestamp,
|
|
410
410
|
dur: Types.Timing.Micro(0),
|
|
411
411
|
pid: this.#processId,
|
|
@@ -422,10 +422,10 @@ export class SamplesIntegrator {
|
|
|
422
422
|
}
|
|
423
423
|
static nativeGroup(nativeName) {
|
|
424
424
|
if (nativeName.startsWith('Parse')) {
|
|
425
|
-
return
|
|
425
|
+
return SamplesIntegrator.NativeGroups.PARSE;
|
|
426
426
|
}
|
|
427
427
|
if (nativeName.startsWith('Compile') || nativeName.startsWith('Recompile')) {
|
|
428
|
-
return
|
|
428
|
+
return SamplesIntegrator.NativeGroups.COMPILE;
|
|
429
429
|
}
|
|
430
430
|
return null;
|
|
431
431
|
}
|
|
@@ -458,8 +458,8 @@ export class SamplesIntegrator {
|
|
|
458
458
|
static createFakeTraceFromCpuProfile(profile, tid) {
|
|
459
459
|
const events = [];
|
|
460
460
|
const threadName = `Thread ${tid}`;
|
|
461
|
-
appendEvent('TracingStartedInPage', { data: { sessionId: '1' } }, 0, 0,
|
|
462
|
-
appendEvent(
|
|
461
|
+
appendEvent('TracingStartedInPage', { data: { sessionId: '1' } }, 0, 0, Types.Events.Phase.METADATA);
|
|
462
|
+
appendEvent(Types.Events.Name.THREAD_NAME, { name: threadName }, 0, 0, Types.Events.Phase.METADATA, '__metadata');
|
|
463
463
|
if (!profile) {
|
|
464
464
|
return { traceEvents: events, metadata: {} };
|
|
465
465
|
}
|
|
@@ -467,13 +467,13 @@ export class SamplesIntegrator {
|
|
|
467
467
|
// panel won't truncate this time period.
|
|
468
468
|
// 'JSRoot' doesn't exist in the new engine and is not the name of an actual trace event, but changing it might break other trace processing tools that rely on this, so we stick with this name.
|
|
469
469
|
// TODO(crbug.com/341234884): consider removing this or clarify why it's required.
|
|
470
|
-
appendEvent('JSRoot', {}, profile.startTime, profile.endTime - profile.startTime,
|
|
470
|
+
appendEvent('JSRoot', {}, profile.startTime, profile.endTime - profile.startTime, Types.Events.Phase.COMPLETE, 'toplevel');
|
|
471
471
|
// TODO: create a `Profile` event instead, as `cpuProfile` is legacy
|
|
472
|
-
appendEvent('CpuProfile', { data: { cpuProfile: profile } }, profile.endTime, 0,
|
|
472
|
+
appendEvent('CpuProfile', { data: { cpuProfile: profile } }, profile.endTime, 0, Types.Events.Phase.COMPLETE);
|
|
473
473
|
return {
|
|
474
474
|
traceEvents: events,
|
|
475
475
|
metadata: {
|
|
476
|
-
dataOrigin:
|
|
476
|
+
dataOrigin: Types.File.DataOrigin.CPU_PROFILE,
|
|
477
477
|
}
|
|
478
478
|
};
|
|
479
479
|
function appendEvent(
|
|
@@ -482,7 +482,7 @@ export class SamplesIntegrator {
|
|
|
482
482
|
const event = {
|
|
483
483
|
cat: cat || 'disabled-by-default-devtools.timeline',
|
|
484
484
|
name,
|
|
485
|
-
ph: ph ||
|
|
485
|
+
ph: ph || Types.Events.Phase.COMPLETE,
|
|
486
486
|
pid: Types.Events.ProcessID(1),
|
|
487
487
|
tid,
|
|
488
488
|
ts: Types.Timing.Micro(ts),
|
|
@@ -496,4 +496,11 @@ export class SamplesIntegrator {
|
|
|
496
496
|
}
|
|
497
497
|
}
|
|
498
498
|
}
|
|
499
|
+
(function (SamplesIntegrator) {
|
|
500
|
+
let NativeGroups;
|
|
501
|
+
(function (NativeGroups) {
|
|
502
|
+
NativeGroups["COMPILE"] = "Compile";
|
|
503
|
+
NativeGroups["PARSE"] = "Parse";
|
|
504
|
+
})(NativeGroups = SamplesIntegrator.NativeGroups || (SamplesIntegrator.NativeGroups = {}));
|
|
505
|
+
})(SamplesIntegrator || (SamplesIntegrator = {}));
|
|
499
506
|
//# sourceMappingURL=SamplesIntegrator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SamplesIntegrator.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/SamplesIntegrator.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Types from '../types/types.js';\n\nimport {milliToMicro} from './Timing.js';\nimport {extractSampleTraceId, makeProfileCall, mergeEventsInOrder, sortTraceEventsInPlace} from './Trace.js';\n\n/**\n * This is a helper that integrates CPU profiling data coming in the\n * shape of samples, with trace events. Samples indicate what the JS\n * stack trace looked at a given point in time, but they don't have\n * duration. The SamplesIntegrator task is to make an approximation\n * of what the duration of each JS call was, given the sample data and\n * given the trace events profiled during that time. At the end of its\n * execution, the SamplesIntegrator returns an array of ProfileCalls\n * (under SamplesIntegrator::buildProfileCalls()), which\n * represent JS calls, with a call frame and duration. These calls have\n * the shape of a complete trace events and can be treated as flame\n * chart entries in the timeline.\n *\n * The approach to build the profile calls consists in tracking the\n * current stack as the following events happen (in order):\n * 1. A sample was done.\n * 2. A trace event started.\n * 3. A trace event ended.\n * Depending on the event and on the data that's coming with it the\n * stack is updated by adding or removing JS calls to it and updating\n * the duration of the calls in the tracking stack.\n *\n * note: Although this approach has been implemented since long ago, and\n * is relatively efficient (adds a complexity over the trace parsing of\n * O(n) where n is the number of samples) it has proven to be faulty.\n * It might be worthwhile experimenting with improvements or with a\n * completely different approach. Improving the approach is tracked in\n * crbug.com/1417439\n */\nexport class SamplesIntegrator {\n /**\n * The result of running the samples integrator. Holds the JS calls\n * with their approximated duration after integrating samples into the\n * trace event tree.\n */\n #constructedProfileCalls: Types.Events.SyntheticProfileCall[] = [];\n /**\n * tracks the state of the JS stack at each point in time to update\n * the profile call durations as new events arrive. This doesn't only\n * happen with new profile calls (in which case we would compare the\n * stack in them) but also with trace events (in which case we would\n * update the duration of the events we are tracking at the moment).\n */\n #currentJSStack: Types.Events.SyntheticProfileCall[] = [];\n /**\n * Process holding the CPU profile and trace events.\n */\n #processId: Types.Events.ProcessID;\n /**\n * Thread holding the CPU profile and trace events.\n */\n #threadId: Types.Events.ThreadID;\n /**\n * Tracks the depth of the JS stack at the moment a trace event starts\n * or ends. It is assumed that for the duration of a trace event, the\n * JS stack's depth cannot decrease, since JS calls that started\n * before a trace event cannot end during the trace event. So as trace\n * events arrive, we store the \"locked\" amount of JS frames that were\n * in the stack before the event came.\n */\n #lockedJsStackDepth: number[] = [];\n /**\n * Used to keep track when samples should be integrated even if they\n * are not children of invocation trace events. This is useful in\n * cases where we can be missing the start of JS invocation events if\n * we start tracing half-way through.\n */\n #fakeJSInvocation = false;\n /**\n * The parsed CPU profile, holding the tree hierarchy of JS frames and\n * the sample data.\n */\n #profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel;\n /**\n * Because GC nodes don't have a stack, we artificially add a stack to\n * them which corresponds to that of the previous sample. This map\n * tracks which node is used for the stack of a GC call.\n * Note that GC samples are not shown in the flamechart, however they\n * are used during the construction of for profile calls, as we can\n * infer information about the duration of the executed code when a\n * GC node is sampled.\n */\n #nodeForGC = new Map<Types.Events.SyntheticProfileCall, CPUProfile.ProfileTreeModel.ProfileNode>();\n\n #engineConfig: Types.Configuration.Configuration;\n #profileId: Types.Events.ProfileID;\n\n /**\n * Keeps track of the individual samples from the CPU Profile.\n * Only used with Debug Mode experiment enabled.\n */\n jsSampleEvents: Types.Events.SyntheticJSSample[] = [];\n\n constructor(\n profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel, profileId: Types.Events.ProfileID,\n pid: Types.Events.ProcessID, tid: Types.Events.ThreadID, configuration?: Types.Configuration.Configuration) {\n this.#profileModel = profileModel;\n this.#threadId = tid;\n this.#processId = pid;\n this.#engineConfig = configuration || Types.Configuration.defaults();\n this.#profileId = profileId;\n }\n\n buildProfileCalls(traceEvents: Types.Events.Event[]): Types.Events.SyntheticProfileCall[] {\n const mergedEvents = mergeEventsInOrder(traceEvents, this.callsFromProfileSamples());\n const stack = [];\n for (let i = 0; i < mergedEvents.length; i++) {\n const event = mergedEvents[i];\n // Because instant trace events have no duration, they don't provide\n // useful information for possible changes in the duration of calls\n // in the JS stack.\n if (event.ph === Types.Events.Phase.INSTANT && !extractSampleTraceId(event)) {\n continue;\n }\n if (stack.length === 0) {\n if (Types.Events.isProfileCall(event)) {\n this.#onProfileCall(event);\n continue;\n }\n stack.push(event);\n this.#onTraceEventStart(event);\n continue;\n }\n\n const parentEvent = stack.at(-1);\n if (parentEvent === undefined) {\n continue;\n }\n const begin = event.ts;\n const parentBegin = parentEvent.ts;\n const parentDuration = parentEvent.dur || 0;\n const parentEnd = parentBegin + parentDuration;\n\n const startsAfterParent = begin >= parentEnd;\n if (startsAfterParent) {\n this.#onTraceEventEnd(parentEvent);\n stack.pop();\n i--;\n continue;\n }\n if (Types.Events.isProfileCall(event)) {\n this.#onProfileCall(event, parentEvent);\n continue;\n }\n this.#onTraceEventStart(event);\n stack.push(event);\n }\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n this.#onTraceEventEnd(last);\n }\n }\n sortTraceEventsInPlace(this.jsSampleEvents);\n return this.#constructedProfileCalls;\n }\n\n #onTraceEventStart(event: Types.Events.Event): void {\n // Top level events cannot be nested into JS frames so we reset\n // the stack when we find one.\n if (event.name === Types.Events.Name.RUN_MICROTASKS || event.name === Types.Events.Name.RUN_TASK) {\n this.#lockedJsStackDepth = [];\n this.#truncateJSStack(0, event.ts);\n this.#fakeJSInvocation = false;\n }\n\n if (this.#fakeJSInvocation) {\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, event.ts);\n this.#fakeJSInvocation = false;\n }\n this.#extractStackTrace(event);\n // Keep track of the call frames in the stack before the event\n // happened. For the duration of this event, these frames cannot\n // change (none can be terminated before this event finishes).\n //\n // Also, every frame that is opened after this event, is considered\n // to be a descendant of the event. So once the event finishes, the\n // frames that were opened after it, need to be closed (see\n // onEndEvent).\n //\n // TODO(crbug.com/1417439):\n // The assumption that every frame opened after an event is a\n // descendant of the event is incorrect. For example, a JS call that\n // parents a trace event might have been sampled after the event was\n // dispatched. In this case the JS call would be discarded if this\n // event isn't an invocation event, otherwise the call will be\n // considered a child of the event. In both cases, the result would\n // be incorrect.\n this.#lockedJsStackDepth.push(this.#currentJSStack.length);\n }\n\n #onProfileCall(event: Types.Events.SyntheticProfileCall, parent?: Types.Events.Event): void {\n if ((parent && Types.Events.isJSInvocationEvent(parent)) || this.#fakeJSInvocation) {\n this.#extractStackTrace(event);\n } else if (Types.Events.isProfileCall(event) && this.#currentJSStack.length === 0) {\n // Force JS Samples to show up even if we are not inside a JS\n // invocation event, because we can be missing the start of JS\n // invocation events if we start tracing half-way through. Pretend\n // we have a top-level JS invocation event.\n this.#fakeJSInvocation = true;\n const stackDepthBefore = this.#currentJSStack.length;\n this.#extractStackTrace(event);\n this.#lockedJsStackDepth.push(stackDepthBefore);\n }\n }\n\n #onTraceEventEnd(event: Types.Events.Event): void {\n // Because the event has ended, any frames that happened after\n // this event are terminated. Frames that are ancestors to this\n // event are extended to cover its ending.\n const endTime = Types.Timing.Micro(event.ts + (event.dur ?? 0));\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, endTime);\n }\n\n /**\n * Builds the initial calls with no duration from samples. Their\n * purpose is to be merged with the trace event array being parsed so\n * that they can be traversed in order with them and their duration\n * can be updated as the SampleIntegrator callbacks are invoked.\n */\n callsFromProfileSamples(): Types.Events.SyntheticProfileCall[] {\n const samples = this.#profileModel.samples;\n const timestamps = this.#profileModel.timestamps;\n if (!samples) {\n return [];\n }\n const calls: Types.Events.SyntheticProfileCall[] = [];\n let prevNode;\n for (let i = 0; i < samples.length; i++) {\n const node = this.#profileModel.nodeByIndex(i);\n const timestamp = milliToMicro(Types.Timing.Milli(timestamps[i]));\n if (!node) {\n continue;\n }\n const call = makeProfileCall(node, this.#profileId, i, timestamp, this.#processId, this.#threadId);\n calls.push(call);\n\n if (this.#engineConfig.debugMode) {\n const traceId = this.#profileModel.traceIds?.[i];\n this.jsSampleEvents.push(this.#makeJSSampleEvent(call, timestamp, traceId));\n }\n if (node.id === this.#profileModel.gcNode?.id && prevNode) {\n // GC samples have no stack, so we just put GC node on top of the\n // last recorded sample. Cache the previous sample for future\n // reference.\n this.#nodeForGC.set(call, prevNode);\n continue;\n }\n prevNode = node;\n }\n return calls;\n }\n\n /**\n * Given a synthetic profile call, returns an array of profile calls\n * representing the stack trace that profile call belongs to based on\n * its nodeId. The input profile call will be at the top of the\n * returned stack (last position), meaning that any other frames that\n * were effectively above it are omitted.\n * @param profileCall\n * @param overrideTimeStamp a custom timestamp to use for the returned\n * profile calls. If not defined, the timestamp of the input\n * profileCall is used instead. This param is useful for example when\n * creating the profile calls for a sample with a trace id, since the\n * timestamp of the corresponding trace event should be used instead\n * of the sample's.\n */\n\n #makeProfileCallsForStack(profileCall: Types.Events.SyntheticProfileCall, overrideTimeStamp?: Types.Timing.Micro):\n Types.Events.SyntheticProfileCall[] {\n let node = this.#profileModel.nodeById(profileCall.nodeId);\n const isGarbageCollection = node?.id === this.#profileModel.gcNode?.id;\n if (isGarbageCollection) {\n // Because GC don't have a stack, we use the stack of the previous\n // sample.\n node = this.#nodeForGC.get(profileCall) || null;\n }\n if (!node) {\n return [];\n }\n // `node.depth` is 0 based, so to set the size of the array we need\n // to add 1 to its value.\n const callFrames = new Array<Types.Events.SyntheticProfileCall>(node.depth + 1 + Number(isGarbageCollection));\n // Add the stack trace in reverse order (bottom first).\n let i = callFrames.length - 1;\n if (isGarbageCollection) {\n // Place the garbage collection call frame on top of the stack.\n callFrames[i--] = profileCall;\n }\n\n // Many of these ProfileCalls will be GC'd later when we estimate the frame\n // durations\n while (node) {\n callFrames[i--] = makeProfileCall(\n node, profileCall.profileId, profileCall.sampleIndex, overrideTimeStamp ?? profileCall.ts, this.#processId,\n this.#threadId);\n node = node.parent;\n }\n return callFrames;\n }\n\n #getStackForSampleTraceId(traceId: number, timestamp: Types.Timing.Micro): Types.Events.SyntheticProfileCall[]|null {\n const nodeId = this.#profileModel.traceIds?.[traceId];\n const node = nodeId && this.#profileModel.nodeById(nodeId);\n const maybeCallForTraceId =\n node && makeProfileCall(node, this.#profileId, -1, timestamp, this.#processId, this.#threadId);\n if (!maybeCallForTraceId) {\n return null;\n }\n if (this.#engineConfig.debugMode) {\n this.jsSampleEvents.push(this.#makeJSSampleEvent(maybeCallForTraceId, timestamp, traceId));\n }\n return this.#makeProfileCallsForStack(maybeCallForTraceId);\n }\n /**\n * Update tracked stack using this event's call stack.\n */\n #extractStackTrace(event: Types.Events.Event): void {\n let stackTrace = this.#currentJSStack;\n if (Types.Events.isProfileCall(event)) {\n stackTrace = this.#makeProfileCallsForStack(event);\n }\n const traceId = extractSampleTraceId(event);\n const maybeCallForTraceId = traceId && this.#getStackForSampleTraceId(traceId, event.ts);\n if (maybeCallForTraceId) {\n stackTrace = maybeCallForTraceId;\n }\n\n SamplesIntegrator.filterStackFrames(stackTrace, this.#engineConfig);\n\n const endTime = event.ts + (event.dur || 0);\n const minFrames = Math.min(stackTrace.length, this.#currentJSStack.length);\n let i;\n // Merge a sample's stack frames with the stack frames we have\n // so far if we detect they are equivalent.\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // ^ t = x1 ^ t = x2\n\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // ^ t = x2\n for (i = this.#lockedJsStackDepth.at(-1) || 0; i < minFrames; ++i) {\n const newFrame = stackTrace[i].callFrame;\n const oldFrame = this.#currentJSStack[i].callFrame;\n if (!SamplesIntegrator.framesAreEqual(newFrame, oldFrame)) {\n break;\n }\n // Scoot the right edge of this callFrame to the right\n this.#currentJSStack[i].dur =\n Types.Timing.Micro(Math.max(this.#currentJSStack[i].dur || 0, endTime - this.#currentJSStack[i].ts));\n }\n\n // If there are call frames in the sample that differ with the stack\n // we have, update the stack, but keeping the common frames in place\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // [-------D------] [E]\n // ^ t = x1 ^ t = x2\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // [E]\n // ^ t = x2\n this.#truncateJSStack(i, event.ts);\n\n for (; i < stackTrace.length; ++i) {\n const call = stackTrace[i];\n if (call.nodeId === this.#profileModel.programNode?.id || call.nodeId === this.#profileModel.root?.id ||\n call.nodeId === this.#profileModel.idleNode?.id || call.nodeId === this.#profileModel.gcNode?.id) {\n // Skip (root), (program) and (idle) frames, since this are not\n // relevant for web profiling and we don't want to show them in\n // the timeline.\n continue;\n }\n this.#currentJSStack.push(call);\n this.#constructedProfileCalls.push(call);\n }\n }\n\n /**\n * When a call stack that differs from the one we are tracking has\n * been detected in the samples, the latter is \"truncated\" by\n * setting the ending time of its call frames and removing the top\n * call frames that aren't shared with the new call stack. This way,\n * we can update the tracked stack with the new call frames on top.\n * @param depth the amount of call frames from bottom to top that\n * should be kept in the tracking stack trace. AKA amount of shared\n * call frames between two stacks.\n * @param time the new end of the call frames in the stack.\n */\n #truncateJSStack(depth: number, time: Types.Timing.Micro): void {\n if (this.#lockedJsStackDepth.length) {\n const lockedDepth = this.#lockedJsStackDepth.at(-1);\n if (lockedDepth && depth < lockedDepth) {\n console.error(`Child stack is shallower (${depth}) than the parent stack (${lockedDepth}) at ${time}`);\n depth = lockedDepth;\n }\n }\n if (this.#currentJSStack.length < depth) {\n console.error(`Trying to truncate higher than the current stack size at ${time}`);\n depth = this.#currentJSStack.length;\n }\n for (let k = 0; k < this.#currentJSStack.length; ++k) {\n this.#currentJSStack[k].dur = Types.Timing.Micro(Math.max(time - this.#currentJSStack[k].ts, 0));\n }\n this.#currentJSStack.length = depth;\n }\n\n #makeJSSampleEvent(call: Types.Events.SyntheticProfileCall, timestamp: Types.Timing.Micro, traceId?: number):\n Types.Events.SyntheticJSSample {\n const JSSampleEvent: Types.Events.SyntheticJSSample = {\n name: Types.Events.Name.JS_SAMPLE,\n cat: 'devtools.timeline',\n args: {\n data: {traceId, stackTrace: this.#makeProfileCallsForStack(call).map(e => e.callFrame)},\n },\n ph: Types.Events.Phase.INSTANT,\n ts: timestamp,\n dur: Types.Timing.Micro(0),\n pid: this.#processId,\n tid: this.#threadId,\n };\n return JSSampleEvent;\n }\n\n static framesAreEqual(frame1: Protocol.Runtime.CallFrame, frame2: Protocol.Runtime.CallFrame): boolean {\n return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName &&\n frame1.lineNumber === frame2.lineNumber;\n }\n\n static showNativeName(name: string, runtimeCallStatsEnabled: boolean): boolean {\n return runtimeCallStatsEnabled && Boolean(SamplesIntegrator.nativeGroup(name));\n }\n\n static nativeGroup(nativeName: string): SamplesIntegrator.NativeGroups|null {\n if (nativeName.startsWith('Parse')) {\n return SamplesIntegrator.NativeGroups.PARSE;\n }\n if (nativeName.startsWith('Compile') || nativeName.startsWith('Recompile')) {\n return SamplesIntegrator.NativeGroups.COMPILE;\n }\n return null;\n }\n\n static isNativeRuntimeFrame(frame: Protocol.Runtime.CallFrame): boolean {\n return frame.url === 'native V8Runtime';\n }\n\n static filterStackFrames(stack: Types.Events.SyntheticProfileCall[], engineConfig: Types.Configuration.Configuration):\n void {\n const showAllEvents = engineConfig.showAllEvents;\n if (showAllEvents) {\n return;\n }\n let previousNativeFrameName: string|null = null;\n let j = 0;\n for (let i = 0; i < stack.length; ++i) {\n const frame = stack[i].callFrame;\n const nativeRuntimeFrame = SamplesIntegrator.isNativeRuntimeFrame(frame);\n if (nativeRuntimeFrame &&\n !SamplesIntegrator.showNativeName(frame.functionName, engineConfig.includeRuntimeCallStats)) {\n continue;\n }\n const nativeFrameName = nativeRuntimeFrame ? SamplesIntegrator.nativeGroup(frame.functionName) : null;\n if (previousNativeFrameName && previousNativeFrameName === nativeFrameName) {\n continue;\n }\n previousNativeFrameName = nativeFrameName;\n stack[j++] = stack[i];\n }\n stack.length = j;\n }\n\n static createFakeTraceFromCpuProfile(profile: Protocol.Profiler.Profile, tid: Types.Events.ThreadID):\n Types.File.TraceFile {\n const events: Types.Events.Event[] = [];\n\n const threadName = `Thread ${tid}`;\n appendEvent('TracingStartedInPage', {data: {sessionId: '1'}}, 0, 0, Types.Events.Phase.METADATA);\n appendEvent(Types.Events.Name.THREAD_NAME, {name: threadName}, 0, 0, Types.Events.Phase.METADATA, '__metadata');\n if (!profile) {\n return {traceEvents: events, metadata: {}};\n }\n\n // Append a root to show the start time of the profile (which is earlier than first sample), so the Performance\n // panel won't truncate this time period.\n // 'JSRoot' doesn't exist in the new engine and is not the name of an actual trace event, but changing it might break other trace processing tools that rely on this, so we stick with this name.\n // TODO(crbug.com/341234884): consider removing this or clarify why it's required.\n appendEvent(\n 'JSRoot', {}, profile.startTime, profile.endTime - profile.startTime, Types.Events.Phase.COMPLETE, 'toplevel');\n\n // TODO: create a `Profile` event instead, as `cpuProfile` is legacy\n appendEvent('CpuProfile', {data: {cpuProfile: profile}}, profile.endTime, 0, Types.Events.Phase.COMPLETE);\n return {\n traceEvents: events,\n metadata: {\n dataOrigin: Types.File.DataOrigin.CPU_PROFILE,\n }\n };\n\n function appendEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n name: string, args: any, ts: number, dur?: number, ph?: Types.Events.Phase, cat?: string): Types.Events.Event {\n const event: Types.Events.Event = {\n cat: cat || 'disabled-by-default-devtools.timeline',\n name,\n ph: ph || Types.Events.Phase.COMPLETE,\n pid: Types.Events.ProcessID(1),\n tid,\n ts: Types.Timing.Micro(ts),\n args,\n };\n\n if (dur) {\n event.dur = Types.Timing.Micro(dur);\n }\n events.push(event);\n return event;\n }\n }\n}\n\nexport namespace SamplesIntegrator {\n export const enum NativeGroups {\n COMPILE = 'Compile',\n PARSE = 'Parse',\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SamplesIntegrator.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/helpers/SamplesIntegrator.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Protocol from '../../../generated/protocol.js';\nimport type * as CPUProfile from '../../cpu_profile/cpu_profile.js';\nimport * as Types from '../types/types.js';\n\nimport {milliToMicro} from './Timing.js';\nimport {extractSampleTraceId, makeProfileCall, mergeEventsInOrder, sortTraceEventsInPlace} from './Trace.js';\n\n/**\n * This is a helper that integrates CPU profiling data coming in the\n * shape of samples, with trace events. Samples indicate what the JS\n * stack trace looked at a given point in time, but they don't have\n * duration. The SamplesIntegrator task is to make an approximation\n * of what the duration of each JS call was, given the sample data and\n * given the trace events profiled during that time. At the end of its\n * execution, the SamplesIntegrator returns an array of ProfileCalls\n * (under SamplesIntegrator::buildProfileCalls()), which\n * represent JS calls, with a call frame and duration. These calls have\n * the shape of a complete trace events and can be treated as flame\n * chart entries in the timeline.\n *\n * The approach to build the profile calls consists in tracking the\n * current stack as the following events happen (in order):\n * 1. A sample was done.\n * 2. A trace event started.\n * 3. A trace event ended.\n * Depending on the event and on the data that's coming with it the\n * stack is updated by adding or removing JS calls to it and updating\n * the duration of the calls in the tracking stack.\n *\n * note: Although this approach has been implemented since long ago, and\n * is relatively efficient (adds a complexity over the trace parsing of\n * O(n) where n is the number of samples) it has proven to be faulty.\n * It might be worthwhile experimenting with improvements or with a\n * completely different approach. Improving the approach is tracked in\n * crbug.com/1417439\n */\nexport class SamplesIntegrator {\n /**\n * The result of running the samples integrator. Holds the JS calls\n * with their approximated duration after integrating samples into the\n * trace event tree.\n */\n #constructedProfileCalls: Types.Events.SyntheticProfileCall[] = [];\n /**\n * tracks the state of the JS stack at each point in time to update\n * the profile call durations as new events arrive. This doesn't only\n * happen with new profile calls (in which case we would compare the\n * stack in them) but also with trace events (in which case we would\n * update the duration of the events we are tracking at the moment).\n */\n #currentJSStack: Types.Events.SyntheticProfileCall[] = [];\n /**\n * Process holding the CPU profile and trace events.\n */\n #processId: Types.Events.ProcessID;\n /**\n * Thread holding the CPU profile and trace events.\n */\n #threadId: Types.Events.ThreadID;\n /**\n * Tracks the depth of the JS stack at the moment a trace event starts\n * or ends. It is assumed that for the duration of a trace event, the\n * JS stack's depth cannot decrease, since JS calls that started\n * before a trace event cannot end during the trace event. So as trace\n * events arrive, we store the \"locked\" amount of JS frames that were\n * in the stack before the event came.\n */\n #lockedJsStackDepth: number[] = [];\n /**\n * Used to keep track when samples should be integrated even if they\n * are not children of invocation trace events. This is useful in\n * cases where we can be missing the start of JS invocation events if\n * we start tracing half-way through.\n */\n #fakeJSInvocation = false;\n /**\n * The parsed CPU profile, holding the tree hierarchy of JS frames and\n * the sample data.\n */\n #profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel;\n /**\n * Because GC nodes don't have a stack, we artificially add a stack to\n * them which corresponds to that of the previous sample. This map\n * tracks which node is used for the stack of a GC call.\n * Note that GC samples are not shown in the flamechart, however they\n * are used during the construction of for profile calls, as we can\n * infer information about the duration of the executed code when a\n * GC node is sampled.\n */\n #nodeForGC = new Map<Types.Events.SyntheticProfileCall, CPUProfile.ProfileTreeModel.ProfileNode>();\n\n #engineConfig: Types.Configuration.Configuration;\n #profileId: Types.Events.ProfileID;\n\n /**\n * Keeps track of the individual samples from the CPU Profile.\n * Only used with Debug Mode experiment enabled.\n */\n jsSampleEvents: Types.Events.SyntheticJSSample[] = [];\n\n constructor(\n profileModel: CPUProfile.CPUProfileDataModel.CPUProfileDataModel, profileId: Types.Events.ProfileID,\n pid: Types.Events.ProcessID, tid: Types.Events.ThreadID, configuration?: Types.Configuration.Configuration) {\n this.#profileModel = profileModel;\n this.#threadId = tid;\n this.#processId = pid;\n this.#engineConfig = configuration || Types.Configuration.defaults();\n this.#profileId = profileId;\n }\n\n buildProfileCalls(traceEvents: Types.Events.Event[]): Types.Events.SyntheticProfileCall[] {\n const mergedEvents = mergeEventsInOrder(traceEvents, this.callsFromProfileSamples());\n const stack = [];\n for (let i = 0; i < mergedEvents.length; i++) {\n const event = mergedEvents[i];\n // Because instant trace events have no duration, they don't provide\n // useful information for possible changes in the duration of calls\n // in the JS stack.\n if (event.ph === Types.Events.Phase.INSTANT && !extractSampleTraceId(event)) {\n continue;\n }\n if (stack.length === 0) {\n if (Types.Events.isProfileCall(event)) {\n this.#onProfileCall(event);\n continue;\n }\n stack.push(event);\n this.#onTraceEventStart(event);\n continue;\n }\n\n const parentEvent = stack.at(-1);\n if (parentEvent === undefined) {\n continue;\n }\n const begin = event.ts;\n const parentBegin = parentEvent.ts;\n const parentDuration = parentEvent.dur || 0;\n const parentEnd = parentBegin + parentDuration;\n\n const startsAfterParent = begin >= parentEnd;\n if (startsAfterParent) {\n this.#onTraceEventEnd(parentEvent);\n stack.pop();\n i--;\n continue;\n }\n if (Types.Events.isProfileCall(event)) {\n this.#onProfileCall(event, parentEvent);\n continue;\n }\n this.#onTraceEventStart(event);\n stack.push(event);\n }\n while (stack.length) {\n const last = stack.pop();\n if (last) {\n this.#onTraceEventEnd(last);\n }\n }\n sortTraceEventsInPlace(this.jsSampleEvents);\n return this.#constructedProfileCalls;\n }\n\n #onTraceEventStart(event: Types.Events.Event): void {\n // Top level events cannot be nested into JS frames so we reset\n // the stack when we find one.\n if (event.name === Types.Events.Name.RUN_MICROTASKS || event.name === Types.Events.Name.RUN_TASK) {\n this.#lockedJsStackDepth = [];\n this.#truncateJSStack(0, event.ts);\n this.#fakeJSInvocation = false;\n }\n\n if (this.#fakeJSInvocation) {\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, event.ts);\n this.#fakeJSInvocation = false;\n }\n this.#extractStackTrace(event);\n // Keep track of the call frames in the stack before the event\n // happened. For the duration of this event, these frames cannot\n // change (none can be terminated before this event finishes).\n //\n // Also, every frame that is opened after this event, is considered\n // to be a descendant of the event. So once the event finishes, the\n // frames that were opened after it, need to be closed (see\n // onEndEvent).\n //\n // TODO(crbug.com/1417439):\n // The assumption that every frame opened after an event is a\n // descendant of the event is incorrect. For example, a JS call that\n // parents a trace event might have been sampled after the event was\n // dispatched. In this case the JS call would be discarded if this\n // event isn't an invocation event, otherwise the call will be\n // considered a child of the event. In both cases, the result would\n // be incorrect.\n this.#lockedJsStackDepth.push(this.#currentJSStack.length);\n }\n\n #onProfileCall(event: Types.Events.SyntheticProfileCall, parent?: Types.Events.Event): void {\n if ((parent && Types.Events.isJSInvocationEvent(parent)) || this.#fakeJSInvocation) {\n this.#extractStackTrace(event);\n } else if (Types.Events.isProfileCall(event) && this.#currentJSStack.length === 0) {\n // Force JS Samples to show up even if we are not inside a JS\n // invocation event, because we can be missing the start of JS\n // invocation events if we start tracing half-way through. Pretend\n // we have a top-level JS invocation event.\n this.#fakeJSInvocation = true;\n const stackDepthBefore = this.#currentJSStack.length;\n this.#extractStackTrace(event);\n this.#lockedJsStackDepth.push(stackDepthBefore);\n }\n }\n\n #onTraceEventEnd(event: Types.Events.Event): void {\n // Because the event has ended, any frames that happened after\n // this event are terminated. Frames that are ancestors to this\n // event are extended to cover its ending.\n const endTime = Types.Timing.Micro(event.ts + (event.dur ?? 0));\n this.#truncateJSStack(this.#lockedJsStackDepth.pop() || 0, endTime);\n }\n\n /**\n * Builds the initial calls with no duration from samples. Their\n * purpose is to be merged with the trace event array being parsed so\n * that they can be traversed in order with them and their duration\n * can be updated as the SampleIntegrator callbacks are invoked.\n */\n callsFromProfileSamples(): Types.Events.SyntheticProfileCall[] {\n const samples = this.#profileModel.samples;\n const timestamps = this.#profileModel.timestamps;\n if (!samples) {\n return [];\n }\n const calls: Types.Events.SyntheticProfileCall[] = [];\n let prevNode;\n for (let i = 0; i < samples.length; i++) {\n const node = this.#profileModel.nodeByIndex(i);\n const timestamp = milliToMicro(Types.Timing.Milli(timestamps[i]));\n if (!node) {\n continue;\n }\n const call = makeProfileCall(node, this.#profileId, i, timestamp, this.#processId, this.#threadId);\n calls.push(call);\n\n if (this.#engineConfig.debugMode) {\n const traceId = this.#profileModel.traceIds?.[i];\n this.jsSampleEvents.push(this.#makeJSSampleEvent(call, timestamp, traceId));\n }\n if (node.id === this.#profileModel.gcNode?.id && prevNode) {\n // GC samples have no stack, so we just put GC node on top of the\n // last recorded sample. Cache the previous sample for future\n // reference.\n this.#nodeForGC.set(call, prevNode);\n continue;\n }\n prevNode = node;\n }\n return calls;\n }\n\n /**\n * Given a synthetic profile call, returns an array of profile calls\n * representing the stack trace that profile call belongs to based on\n * its nodeId. The input profile call will be at the top of the\n * returned stack (last position), meaning that any other frames that\n * were effectively above it are omitted.\n * @param profileCall\n * @param overrideTimeStamp a custom timestamp to use for the returned\n * profile calls. If not defined, the timestamp of the input\n * profileCall is used instead. This param is useful for example when\n * creating the profile calls for a sample with a trace id, since the\n * timestamp of the corresponding trace event should be used instead\n * of the sample's.\n */\n\n #makeProfileCallsForStack(profileCall: Types.Events.SyntheticProfileCall, overrideTimeStamp?: Types.Timing.Micro):\n Types.Events.SyntheticProfileCall[] {\n let node = this.#profileModel.nodeById(profileCall.nodeId);\n const isGarbageCollection = node?.id === this.#profileModel.gcNode?.id;\n if (isGarbageCollection) {\n // Because GC don't have a stack, we use the stack of the previous\n // sample.\n node = this.#nodeForGC.get(profileCall) || null;\n }\n if (!node) {\n return [];\n }\n // `node.depth` is 0 based, so to set the size of the array we need\n // to add 1 to its value.\n const callFrames = new Array<Types.Events.SyntheticProfileCall>(node.depth + 1 + Number(isGarbageCollection));\n // Add the stack trace in reverse order (bottom first).\n let i = callFrames.length - 1;\n if (isGarbageCollection) {\n // Place the garbage collection call frame on top of the stack.\n callFrames[i--] = profileCall;\n }\n\n // Many of these ProfileCalls will be GC'd later when we estimate the frame\n // durations\n while (node) {\n callFrames[i--] = makeProfileCall(\n node, profileCall.profileId, profileCall.sampleIndex, overrideTimeStamp ?? profileCall.ts, this.#processId,\n this.#threadId);\n node = node.parent;\n }\n return callFrames;\n }\n\n #getStackForSampleTraceId(traceId: number, timestamp: Types.Timing.Micro): Types.Events.SyntheticProfileCall[]|null {\n const nodeId = this.#profileModel.traceIds?.[traceId];\n const node = nodeId && this.#profileModel.nodeById(nodeId);\n const maybeCallForTraceId =\n node && makeProfileCall(node, this.#profileId, -1, timestamp, this.#processId, this.#threadId);\n if (!maybeCallForTraceId) {\n return null;\n }\n if (this.#engineConfig.debugMode) {\n this.jsSampleEvents.push(this.#makeJSSampleEvent(maybeCallForTraceId, timestamp, traceId));\n }\n return this.#makeProfileCallsForStack(maybeCallForTraceId);\n }\n /**\n * Update tracked stack using this event's call stack.\n */\n #extractStackTrace(event: Types.Events.Event): void {\n let stackTrace = this.#currentJSStack;\n if (Types.Events.isProfileCall(event)) {\n stackTrace = this.#makeProfileCallsForStack(event);\n }\n const traceId = extractSampleTraceId(event);\n const maybeCallForTraceId = traceId && this.#getStackForSampleTraceId(traceId, event.ts);\n if (maybeCallForTraceId) {\n stackTrace = maybeCallForTraceId;\n }\n\n SamplesIntegrator.filterStackFrames(stackTrace, this.#engineConfig);\n\n const endTime = event.ts + (event.dur || 0);\n const minFrames = Math.min(stackTrace.length, this.#currentJSStack.length);\n let i;\n // Merge a sample's stack frames with the stack frames we have\n // so far if we detect they are equivalent.\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // ^ t = x1 ^ t = x2\n\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // ^ t = x2\n for (i = this.#lockedJsStackDepth.at(-1) || 0; i < minFrames; ++i) {\n const newFrame = stackTrace[i].callFrame;\n const oldFrame = this.#currentJSStack[i].callFrame;\n if (!SamplesIntegrator.framesAreEqual(newFrame, oldFrame)) {\n break;\n }\n // Scoot the right edge of this callFrame to the right\n this.#currentJSStack[i].dur =\n Types.Timing.Micro(Math.max(this.#currentJSStack[i].dur || 0, endTime - this.#currentJSStack[i].ts));\n }\n\n // If there are call frames in the sample that differ with the stack\n // we have, update the stack, but keeping the common frames in place\n // Graphically\n // This:\n // Current stack trace Sample\n // [-------A------] [A]\n // [-------B------] [B]\n // [-------C------] [C]\n // [-------D------] [E]\n // ^ t = x1 ^ t = x2\n // Becomes this:\n // New stack trace after merge\n // [--------A-------]\n // [--------B-------]\n // [--------C-------]\n // [E]\n // ^ t = x2\n this.#truncateJSStack(i, event.ts);\n\n for (; i < stackTrace.length; ++i) {\n const call = stackTrace[i];\n if (call.nodeId === this.#profileModel.programNode?.id || call.nodeId === this.#profileModel.root?.id ||\n call.nodeId === this.#profileModel.idleNode?.id || call.nodeId === this.#profileModel.gcNode?.id) {\n // Skip (root), (program) and (idle) frames, since this are not\n // relevant for web profiling and we don't want to show them in\n // the timeline.\n continue;\n }\n this.#currentJSStack.push(call);\n this.#constructedProfileCalls.push(call);\n }\n }\n\n /**\n * When a call stack that differs from the one we are tracking has\n * been detected in the samples, the latter is \"truncated\" by\n * setting the ending time of its call frames and removing the top\n * call frames that aren't shared with the new call stack. This way,\n * we can update the tracked stack with the new call frames on top.\n * @param depth the amount of call frames from bottom to top that\n * should be kept in the tracking stack trace. AKA amount of shared\n * call frames between two stacks.\n * @param time the new end of the call frames in the stack.\n */\n #truncateJSStack(depth: number, time: Types.Timing.Micro): void {\n if (this.#lockedJsStackDepth.length) {\n const lockedDepth = this.#lockedJsStackDepth.at(-1);\n if (lockedDepth && depth < lockedDepth) {\n console.error(`Child stack is shallower (${depth}) than the parent stack (${lockedDepth}) at ${time}`);\n depth = lockedDepth;\n }\n }\n if (this.#currentJSStack.length < depth) {\n console.error(`Trying to truncate higher than the current stack size at ${time}`);\n depth = this.#currentJSStack.length;\n }\n for (let k = 0; k < this.#currentJSStack.length; ++k) {\n this.#currentJSStack[k].dur = Types.Timing.Micro(Math.max(time - this.#currentJSStack[k].ts, 0));\n }\n this.#currentJSStack.length = depth;\n }\n\n #makeJSSampleEvent(call: Types.Events.SyntheticProfileCall, timestamp: Types.Timing.Micro, traceId?: number):\n Types.Events.SyntheticJSSample {\n const JSSampleEvent: Types.Events.SyntheticJSSample = {\n name: Types.Events.Name.JS_SAMPLE,\n cat: 'devtools.timeline',\n args: {\n data: {traceId, stackTrace: this.#makeProfileCallsForStack(call).map(e => e.callFrame)},\n },\n ph: Types.Events.Phase.INSTANT,\n ts: timestamp,\n dur: Types.Timing.Micro(0),\n pid: this.#processId,\n tid: this.#threadId,\n };\n return JSSampleEvent;\n }\n\n static framesAreEqual(frame1: Protocol.Runtime.CallFrame, frame2: Protocol.Runtime.CallFrame): boolean {\n return frame1.scriptId === frame2.scriptId && frame1.functionName === frame2.functionName &&\n frame1.lineNumber === frame2.lineNumber;\n }\n\n static showNativeName(name: string, runtimeCallStatsEnabled: boolean): boolean {\n return runtimeCallStatsEnabled && Boolean(SamplesIntegrator.nativeGroup(name));\n }\n\n static nativeGroup(nativeName: string): SamplesIntegrator.NativeGroups|null {\n if (nativeName.startsWith('Parse')) {\n return SamplesIntegrator.NativeGroups.PARSE;\n }\n if (nativeName.startsWith('Compile') || nativeName.startsWith('Recompile')) {\n return SamplesIntegrator.NativeGroups.COMPILE;\n }\n return null;\n }\n\n static isNativeRuntimeFrame(frame: Protocol.Runtime.CallFrame): boolean {\n return frame.url === 'native V8Runtime';\n }\n\n static filterStackFrames(stack: Types.Events.SyntheticProfileCall[], engineConfig: Types.Configuration.Configuration):\n void {\n const showAllEvents = engineConfig.showAllEvents;\n if (showAllEvents) {\n return;\n }\n let previousNativeFrameName: string|null = null;\n let j = 0;\n for (let i = 0; i < stack.length; ++i) {\n const frame = stack[i].callFrame;\n const nativeRuntimeFrame = SamplesIntegrator.isNativeRuntimeFrame(frame);\n if (nativeRuntimeFrame &&\n !SamplesIntegrator.showNativeName(frame.functionName, engineConfig.includeRuntimeCallStats)) {\n continue;\n }\n const nativeFrameName = nativeRuntimeFrame ? SamplesIntegrator.nativeGroup(frame.functionName) : null;\n if (previousNativeFrameName && previousNativeFrameName === nativeFrameName) {\n continue;\n }\n previousNativeFrameName = nativeFrameName;\n stack[j++] = stack[i];\n }\n stack.length = j;\n }\n\n static createFakeTraceFromCpuProfile(profile: Protocol.Profiler.Profile, tid: Types.Events.ThreadID):\n Types.File.TraceFile {\n const events: Types.Events.Event[] = [];\n\n const threadName = `Thread ${tid}`;\n appendEvent('TracingStartedInPage', {data: {sessionId: '1'}}, 0, 0, Types.Events.Phase.METADATA);\n appendEvent(Types.Events.Name.THREAD_NAME, {name: threadName}, 0, 0, Types.Events.Phase.METADATA, '__metadata');\n if (!profile) {\n return {traceEvents: events, metadata: {}};\n }\n\n // Append a root to show the start time of the profile (which is earlier than first sample), so the Performance\n // panel won't truncate this time period.\n // 'JSRoot' doesn't exist in the new engine and is not the name of an actual trace event, but changing it might break other trace processing tools that rely on this, so we stick with this name.\n // TODO(crbug.com/341234884): consider removing this or clarify why it's required.\n appendEvent(\n 'JSRoot', {}, profile.startTime, profile.endTime - profile.startTime, Types.Events.Phase.COMPLETE, 'toplevel');\n\n // TODO: create a `Profile` event instead, as `cpuProfile` is legacy\n appendEvent('CpuProfile', {data: {cpuProfile: profile}}, profile.endTime, 0, Types.Events.Phase.COMPLETE);\n return {\n traceEvents: events,\n metadata: {\n dataOrigin: Types.File.DataOrigin.CPU_PROFILE,\n }\n };\n\n function appendEvent(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n name: string, args: any, ts: number, dur?: number, ph?: Types.Events.Phase, cat?: string): Types.Events.Event {\n const event: Types.Events.Event = {\n cat: cat || 'disabled-by-default-devtools.timeline',\n name,\n ph: ph || Types.Events.Phase.COMPLETE,\n pid: Types.Events.ProcessID(1),\n tid,\n ts: Types.Timing.Micro(ts),\n args,\n };\n\n if (dur) {\n event.dur = Types.Timing.Micro(dur);\n }\n events.push(event);\n return event;\n }\n }\n}\n\nexport namespace SamplesIntegrator {\n export enum NativeGroups {\n COMPILE = 'Compile',\n PARSE = 'Parse',\n }\n}\n"]}
|