Skip to content

Commit 3dc6f2b

Browse files
authored
Improve the import of profiles generated from clang -ftime-trace=file.json (#5714)
2 changes: - make the content of event.args.detail visible on markers (this shows which source file is being processed) - isMainThread = true when pid == tid (will work only on Linux, but will still be a big relief there to have the actually useful thread at the top) Example profile: https://share.firefox.dev/4rW0x7q
2 parents 2ce8ab6 + 38eb6ad commit 3dc6f2b

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

src/profile-logic/import/chrome.ts

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

src/test/unit/__snapshots__/profile-conversion.test.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445793,7 +445793,7 @@ Object {
445793445793
"resource": Array [],
445794445794
"source": Array [],
445795445795
},
445796-
"isMainThread": false,
445796+
"isMainThread": true,
445797445797
"markers": Object {
445798445798
"category": Array [
445799445799
0,

0 commit comments

Comments
 (0)