@@ -8,26 +8,32 @@ import * as Types from '../types/types.js';
88import type { HandlerName } from './types.js' ;
99import { data as userTimingsData } from './UserTimingsHandler.js' ;
1010
11- const extensionFlameChartEntries : Types . Extensions . SyntheticExtensionTrackEntry [ ] = [ ] ;
11+ const extensionTrackEntries : Types . Extensions . SyntheticExtensionTrackEntry [ ] = [ ] ;
1212const extensionTrackData : Types . Extensions . ExtensionTrackData [ ] = [ ] ;
1313const extensionMarkers : Types . Extensions . SyntheticExtensionMarker [ ] = [ ] ;
1414const entryToNode : Map < Types . Events . Event , Helpers . TreeHelpers . TraceEntryNode > = new Map ( ) ;
15+ const timeStampByName : Map < string , Types . Events . ConsoleTimeStamp > = new Map ( ) ;
16+
17+ const syntheticConsoleEntriesForTimingsTrack : Types . Events . SyntheticConsoleTimeStamp [ ] = [ ] ;
1518
1619export interface ExtensionTraceData {
1720 extensionTrackData : readonly Types . Extensions . ExtensionTrackData [ ] ;
1821 extensionMarkers : readonly Types . Extensions . SyntheticExtensionMarker [ ] ;
1922 entryToNode : Map < Types . Events . Event , Helpers . TreeHelpers . TraceEntryNode > ;
23+ syntheticConsoleEntriesForTimingsTrack : Types . Events . SyntheticConsoleTimeStamp [ ] ;
2024}
2125
2226export function handleEvent ( _event : Types . Events . Event ) : void {
2327 // Implementation not needed because data is sourced from UserTimingsHandler
2428}
2529
2630export function reset ( ) : void {
27- extensionFlameChartEntries . length = 0 ;
31+ extensionTrackEntries . length = 0 ;
32+ syntheticConsoleEntriesForTimingsTrack . length = 0 ;
2833 extensionTrackData . length = 0 ;
2934 extensionMarkers . length = 0 ;
3035 entryToNode . clear ( ) ;
36+ timeStampByName . clear ( ) ;
3137}
3238
3339export async function finalize ( ) : Promise < void > {
@@ -39,14 +45,127 @@ function createExtensionFlameChartEntries(): void {
3945 const marks : readonly Types . Events . PerformanceMark [ ] = userTimingsData ( ) . performanceMarks ;
4046 const mergedRawExtensionEvents = Helpers . Trace . mergeEventsInOrder ( pairedMeasures , marks ) ;
4147
42- extractExtensionEntries ( mergedRawExtensionEvents ) ;
43- Helpers . Extensions . buildTrackDataFromExtensionEntries ( extensionFlameChartEntries , extensionTrackData , entryToNode ) ;
48+ extractPerformanceAPIExtensionEntries ( mergedRawExtensionEvents ) ;
49+ extractConsoleAPIExtensionEntries ( ) ;
50+ // extensionTrackEntries is filled by the above two calls.
51+ Helpers . Trace . sortTraceEventsInPlace ( extensionTrackEntries ) ;
52+ Helpers . Extensions . buildTrackDataFromExtensionEntries ( extensionTrackEntries , extensionTrackData , entryToNode ) ;
53+ }
54+
55+ /**
56+ * Extracts extension entries from console.timeStamp events.
57+ *
58+ * Entries are built by pairing `console.timeStamp` events based on
59+ * their names. When a `console.timeStamp` event includes a `start`
60+ * argument (and optionally an `end` argument), it attempts to find
61+ * previously recorded `console.timeStamp` events with names matching
62+ * the `start` and `end` values. These matching events are then used to
63+ * determine the start and end times of the new entry.
64+ *
65+ * If a `console.timeStamp` event includes data for a custom track
66+ * (specified by the `track` argument), an extension track entry is
67+ * created and added to the `extensionTrackEntries` array. These entries
68+ * are used to visualize custom tracks in the Performance panel.
69+ *
70+ * If a `console.timeStamp` event includes data for a custom track
71+ * (specified by the `track` argument), an extension track entry is
72+ * created and added to the `extensionTrackEntries` array. These entries
73+ * are used to visualize custom tracks in the Performance panel.
74+ *
75+ * If a `console.timeStamp` event does not specify a custom track but
76+ * includes a start and/or end time (referencing other
77+ * `console.timeStamp` names), a synthetic console time stamp entry is
78+ * created and added to the `syntheticConsoleEntriesForTimingsTrack`
79+ * array. These entries are displayed in the "Timings" track.
80+ */
81+ export function extractConsoleAPIExtensionEntries ( ) : void {
82+ const consoleTimeStamps : readonly Types . Events . ConsoleTimeStamp [ ] = userTimingsData ( ) . timestampEvents ;
83+ for ( const currentTimeStamp of consoleTimeStamps ) {
84+ const timeStampName = String ( currentTimeStamp . args . data . name ) ;
85+ timeStampByName . set ( timeStampName , currentTimeStamp ) ;
86+ const extensionData = extensionDataInConsoleTimeStamp ( currentTimeStamp ) ;
87+ const startName = currentTimeStamp . args . data . start ;
88+ const endName = currentTimeStamp . args . data . end ;
89+ if ( ! extensionData && ! startName && ! endName ) {
90+ continue ;
91+ }
92+ const startTimeStamp = startName ? timeStampByName . get ( String ( startName ) ) : undefined ;
93+ const endTimeStamp = endName ? timeStampByName . get ( String ( endName ) ) : undefined ;
94+ if ( endTimeStamp && ! startTimeStamp ) {
95+ // Invalid data
96+ continue ;
97+ }
98+ const entryStartTime = startTimeStamp ?. ts ?? currentTimeStamp . ts ;
99+ const entryEndTime = endTimeStamp ?. ts ?? currentTimeStamp . ts ;
100+ if ( extensionData ) {
101+ const unregisteredExtensionEntry : Omit < Types . Extensions . SyntheticExtensionTrackEntry , '_tag' > = {
102+ ...currentTimeStamp ,
103+ name : timeStampName ,
104+ cat : 'devtools.extension' ,
105+ args : extensionData ,
106+ rawSourceEvent : currentTimeStamp ,
107+ dur : Types . Timing . MicroSeconds ( entryEndTime - entryStartTime ) ,
108+ ts : entryStartTime ,
109+ } ;
110+ const extensionEntry =
111+ Helpers . SyntheticEvents . SyntheticEventsManager . getActiveManager ( )
112+ . registerSyntheticEvent < Types . Extensions . SyntheticExtensionTrackEntry > ( unregisteredExtensionEntry ) ;
113+ extensionTrackEntries . push ( extensionEntry ) ;
114+ continue ;
115+ }
116+ // If no extension data is found in the entry (no custom track name
117+ // was passed), but the entry has a duration. we still save it here
118+ // to be added in the timings track. Note that timings w/o duration
119+ // and extension data are already handled by the UserTimingsHandler.
120+ const unregisteredSyntheticTimeStamp : Omit < Types . Events . SyntheticConsoleTimeStamp , '_tag' > = {
121+ ...currentTimeStamp ,
122+ name : timeStampName ,
123+ cat : 'disabled-by-default-v8.inspector' ,
124+ ph : Types . Events . Phase . COMPLETE ,
125+ ts : entryStartTime ,
126+ dur : Types . Timing . MicroSeconds ( entryEndTime - entryStartTime ) ,
127+ rawSourceEvent : currentTimeStamp
128+ } ;
129+ const syntheticTimeStamp =
130+ Helpers . SyntheticEvents . SyntheticEventsManager . getActiveManager ( )
131+ . registerSyntheticEvent < Types . Events . SyntheticConsoleTimeStamp > ( unregisteredSyntheticTimeStamp ) ;
132+ syntheticConsoleEntriesForTimingsTrack . push ( syntheticTimeStamp ) ;
133+ }
44134}
45135
46- export function extractExtensionEntries ( timings : ( Types . Events . SyntheticUserTimingPair | Types . Events . PerformanceMark ) [ ] ) :
47- void {
136+ /**
137+ * Extracts extension entries from Performance API events (marks and
138+ * measures).
139+ * It specifically looks for events that contain extension-specific data
140+ * within their `detail` property.
141+ *
142+ * If an event's `detail` property can be parsed as a JSON object and
143+ * contains a `devtools` field with a valid extension payload, a
144+ * synthetic extension entry is created. The type of extension entry
145+ * created depends on the payload:
146+ *
147+ * - If the payload conforms to `ExtensionPayloadMarker`, a
148+ * `SyntheticExtensionMarker` is created and added to the
149+ * `extensionMarkers` array. These markers represent single points in
150+ * time.
151+ * - If the payload conforms to `ExtensionPayloadTrackEntry`, a
152+ * `SyntheticExtensionTrackEntry` is created and added to the
153+ * `extensionTrackEntries` array. These entries represent events with
154+ * a duration and are displayed on custom tracks in the Performance
155+ * panel.
156+ *
157+ * **Note:** Only events with a `detail` property that contains valid
158+ * extension data are processed. Other `performance.mark` and
159+ * `performance.measure` events are ignored.
160+ *
161+ * @param timings An array of `SyntheticUserTimingPair` or
162+ * `PerformanceMark` events, typically obtained from the
163+ * `UserTimingsHandler`.
164+ */
165+ export function extractPerformanceAPIExtensionEntries (
166+ timings : ( Types . Events . SyntheticUserTimingPair | Types . Events . PerformanceMark ) [ ] ) : void {
48167 for ( const timing of timings ) {
49- const extensionPayload = extensionDataInTiming ( timing ) ;
168+ const extensionPayload = extensionDataInPerformanceTiming ( timing ) ;
50169 if ( ! extensionPayload ) {
51170 // Not an extension user timing.
52171 continue ;
@@ -78,14 +197,15 @@ export function extractExtensionEntries(timings: (Types.Events.SyntheticUserTimi
78197 Helpers . SyntheticEvents . SyntheticEventsManager . getActiveManager ( )
79198 . registerSyntheticEvent < Types . Extensions . SyntheticExtensionTrackEntry > (
80199 extensionSyntheticEntry as Omit < Types . Extensions . SyntheticExtensionTrackEntry , '_tag' > ) ;
81- extensionFlameChartEntries . push ( extensionTrackEntry ) ;
200+ extensionTrackEntries . push ( extensionTrackEntry ) ;
82201 continue ;
83202 }
84203 }
85204}
86205
87- export function extensionDataInTiming ( timing : Types . Events . SyntheticUserTimingPair |
88- Types . Events . PerformanceMark ) : Types . Extensions . ExtensionDataPayload | null {
206+ export function extensionDataInPerformanceTiming ( timing : Types . Events . SyntheticUserTimingPair |
207+ Types . Events . PerformanceMark ) : Types . Extensions . ExtensionDataPayload |
208+ null {
89209 const timingDetail =
90210 Types . Events . isPerformanceMark ( timing ) ? timing . args . data ?. detail : timing . args . data . beginEvent . args . detail ;
91211 if ( ! timingDetail ) {
@@ -112,12 +232,49 @@ export function extensionDataInTiming(timing: Types.Events.SyntheticUserTimingPa
112232 return null ;
113233 }
114234}
235+ /**
236+ * Extracts extension data from a `console.timeStamp` event.
237+ *
238+ * Checks if a `console.timeStamp` event contains data intended for
239+ * creating a custom track entry in the DevTools Performance panel. It
240+ * specifically looks for a `track` argument within the event's data.
241+ *
242+ * If a `track` argument is present (and not an empty string), the
243+ * function constructs an `ExtensionTrackEntryPayload` object containing
244+ * the track name, an optional color, an optional track group. This
245+ * payload is then used to create a `SyntheticExtensionTrackEntry`.
246+ *
247+ * **Note:** The `color` argument is optional and its type is validated
248+ * against a predefined palette (see
249+ * `ExtensionUI::extensionEntryColor`).
250+ *
251+ * @param timeStamp The `ConsoleTimeStamp` event to extract data from.
252+ * @return An `ExtensionTrackEntryPayload` object if the event contains
253+ * valid extension data for a track entry, or `null` otherwise.
254+ */
255+ export function extensionDataInConsoleTimeStamp ( timeStamp : Types . Events . ConsoleTimeStamp ) :
256+ Types . Extensions . ExtensionTrackEntryPayload | null {
257+ const trackName = timeStamp . args . data . track ;
258+ if ( trackName === '' || trackName === undefined ) {
259+ return null ;
260+ }
261+ return {
262+ // the color is defaulted to primary if it's value isn't one from
263+ // the defined palette (see ExtensionUI::extensionEntryColor) so
264+ // we don't need to check the value is valid here.
265+ color : String ( timeStamp . args . data . color ) as Types . Extensions . ExtensionTrackEntryPayload [ 'color' ] ,
266+ track : String ( trackName ) ,
267+ dataType : 'track-entry' ,
268+ trackGroup : timeStamp . args . data . trackGroup !== undefined ? String ( timeStamp . args . data . trackGroup ) : undefined
269+ } ;
270+ }
115271
116272export function data ( ) : ExtensionTraceData {
117273 return {
118274 entryToNode,
119- extensionTrackData : [ ...extensionTrackData ] ,
120- extensionMarkers : [ ...extensionMarkers ] ,
275+ extensionTrackData,
276+ extensionMarkers,
277+ syntheticConsoleEntriesForTimingsTrack,
121278 } ;
122279}
123280
0 commit comments