@@ -339,7 +339,8 @@ function getThreadInfo(
339339 if ( threadNameEvent ) {
340340 thread . name = threadNameEvent . args . name ;
341341 thread . isMainThread =
342- thread . name . startsWith ( 'Cr' ) && thread . name . endsWith ( 'Main' ) ;
342+ ( thread . name . startsWith ( 'Cr' ) && thread . name . endsWith ( 'Main' ) ) ||
343+ ( ! ! chunk . pid && chunk . pid === chunk . tid ) ;
343344 }
344345
345346 const processNameEvent = findEvent < ProcessNameEvent > (
@@ -940,6 +941,14 @@ function extractMarkers(
940941 } ,
941942 ] ;
942943
944+ // Map to store begin event detail field for pairing with end events.
945+ // For async events (b/e), key is "pid:tid:id:name"
946+ // For duration events (B/E), key is "pid:tid:name"
947+ const beginEventDetail : Map < string , string > = new Map ( ) ;
948+
949+ // Track whether we've added the EventWithDetail schema
950+ let hasEventWithDetailSchema = false ;
951+
943952 for ( const [ name , events ] of eventsByName . entries ( ) ) {
944953 if (
945954 name === 'Profile' ||
@@ -988,11 +997,35 @@ function extractMarkers(
988997 const { thread } = threadInfo ;
989998 const { markers } = thread ;
990999 let argData :
991- | ( object & { type2 ?: unknown ; category2 ?: unknown } )
1000+ | ( object & { type2 ?: unknown ; category2 ?: unknown ; detail ?: string } )
9921001 | null = null ;
9931002 if ( 'args' in event && event . args && typeof event . args === 'object' ) {
994- argData = event . args . data || null ;
1003+ // Some trace events have args.data, but others have args fields directly
1004+ // (e.g., "Source" markers have args.detail).
1005+ if ( event . args . data ) {
1006+ argData = event . args . data ;
1007+ } else if (
1008+ 'detail' in event . args &&
1009+ typeof event . args . detail === 'string'
1010+ ) {
1011+ argData = { detail : event . args . detail } ;
1012+ }
1013+ }
1014+
1015+ // For end events (E/e), try to use the detail from the corresponding begin event
1016+ if ( ( event . ph === 'E' || event . ph === 'e' ) && ! argData ) {
1017+ // Generate key for looking up the begin event detail
1018+ // For async events (b/e), use id; for duration events (B/E), use name only
1019+ const key =
1020+ event . ph === 'e' && 'id' in event
1021+ ? `${ event . pid } :${ event . tid } :${ event . id } :${ name } `
1022+ : `${ event . pid } :${ event . tid } :${ name } ` ;
1023+ const detail = beginEventDetail . get ( key ) ;
1024+ if ( detail ) {
1025+ argData = { detail } ;
1026+ }
9951027 }
1028+
9961029 markers . name . push ( stringTable . indexForString ( name ) ) ;
9971030 markers . category . push ( otherCategoryIndex ) ;
9981031
@@ -1003,9 +1036,32 @@ function extractMarkers(
10031036 argData . category2 = argData . category ;
10041037 }
10051038
1039+ // Add EventWithDetail schema the first time we encounter a detail field
1040+ if ( argData ?. detail && ! hasEventWithDetailSchema ) {
1041+ profile . meta . markerSchema . push ( {
1042+ // Generic schema for Chrome trace event markers with a detail field.
1043+ // This is used when compiling with clang -ftime-trace=file.json, which
1044+ // generates Source markers, ParseDeclarationOrFunctionDefinition markers,
1045+ // and similar compiler events with file paths or location details.
1046+ name : 'EventWithDetail' ,
1047+ chartLabel : '{marker.data.detail}' ,
1048+ tooltipLabel : '{marker.name}: {marker.data.detail}' ,
1049+ tableLabel : '{marker.data.detail}' ,
1050+ display : [ 'marker-chart' , 'marker-table' ] ,
1051+ fields : [
1052+ {
1053+ key : 'detail' ,
1054+ label : 'Details' ,
1055+ format : 'string' ,
1056+ } ,
1057+ ] ,
1058+ } ) ;
1059+ hasEventWithDetailSchema = true ;
1060+ }
1061+
10061062 const newData = {
10071063 ...argData ,
1008- type : name ,
1064+ type : argData ?. detail ? 'EventWithDetail' : name ,
10091065 category : event . cat ,
10101066 } ;
10111067
@@ -1026,13 +1082,29 @@ function extractMarkers(
10261082 markers . startTime . push ( time ) ;
10271083 markers . endTime . push ( null ) ;
10281084 markers . phase . push ( INTERVAL_START ) ;
1085+
1086+ // Store the detail field from begin event so it can be used for the corresponding end event
1087+ if ( argData ?. detail ) {
1088+ const key =
1089+ event . ph === 'b' && 'id' in event
1090+ ? `${ event . pid } :${ event . tid } :${ event . id } :${ name } `
1091+ : `${ event . pid } :${ event . tid } :${ name } ` ;
1092+ beginEventDetail . set ( key , argData . detail ) ;
1093+ }
10291094 } else if ( event . ph === 'E' || event . ph === 'e' ) {
10301095 // Duration or Async Event End
10311096 // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.nso4gcezn7n1
10321097 // The 'E' and 'e' phase stand for "end", and is the Chrome equivalent of IntervalEnd.
10331098 markers . startTime . push ( null ) ;
10341099 markers . endTime . push ( time ) ;
10351100 markers . phase . push ( INTERVAL_END ) ;
1101+
1102+ // Clean up the stored begin event detail
1103+ const key =
1104+ event . ph === 'e' && 'id' in event
1105+ ? `${ event . pid } :${ event . tid } :${ event . id } :${ name } `
1106+ : `${ event . pid } :${ event . tid } :${ name } ` ;
1107+ beginEventDetail . delete ( key ) ;
10361108 } else {
10371109 // Instant Event
10381110 // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.lenwiilchoxp
0 commit comments