Skip to content

Commit

Permalink
Improve hermes profile frame keys to better group frames (#459)
Browse files Browse the repository at this point in the history
Because all args are serialized in the key for hermes profiles, frames were not properly getting grouped since the "parent" property was different. This PR ensures that the frame key is properly constructed from the function name, file name, line + column number.

| Before | After |
| ----- | ----- |
| <img width="1727" alt="Screenshot 2023-12-27 at 2 25 32 PM" src="https://github.com/jlfwong/speedscope/assets/9957046/4ec04653-5a80-4f34-9506-48e0eb415983"> | <img width="1728" alt="Screenshot 2023-12-27 at 2 26 02 PM" src="https://github.com/jlfwong/speedscope/assets/9957046/c3edc447-e8ad-4757-8576-cbb8c27eafe3"> |
| <img width="1720" alt="Screenshot 2023-12-27 at 2 13 37 PM" src="https://github.com/jlfwong/speedscope/assets/9957046/10194aba-8f26-48ca-bf15-06917b44ea99"> | <img width="1728" alt="Screenshot 2023-12-27 at 2 14 20 PM" src="https://github.com/jlfwong/speedscope/assets/9957046/75c32401-1705-4b23-b71a-5f0a720160dd"> |
  • Loading branch information
zacharyfmarion committed Dec 28, 2023
1 parent 3f3da22 commit e9a17d5
Show file tree
Hide file tree
Showing 4 changed files with 210 additions and 7 deletions.
156 changes: 156 additions & 0 deletions sample/profiles/trace-event/hermes-multiple-frames.json
@@ -0,0 +1,156 @@
[
{
"pid":0,
"tid":0,
"ph":"B",
"name":"[root]",
"ts":0,
"args":{
"name":"[root]",
"category":"root",
"url":null,
"line":null,
"column":null,
"params":null,
"allocatedCategory":"root",
"allocatedName":"[root]"
}
},
{
"pid":0,
"tid":0,
"ph":"B",
"name":"beta",
"ts":1,
"args":{
"line":54,
"column":12,
"funcLine":"1",
"funcColumn":"1",
"name":"beta",
"category":"JavaScript",
"parent":1,
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"params":null,
"allocatedCategory":"JavaScript",
"allocatedName":"beta"
}
},
{
"pid":0,
"tid":0,
"ph":"E",
"name":"beta",
"ts":2,
"args":{
"line":54,
"column":12,
"funcLine":"1",
"funcColumn":"1",
"name":"beta",
"category":"JavaScript",
"parent":1,
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"params":null,
"allocatedCategory":"JavaScript",
"allocatedName":"beta"
}
},
{
"pid":0,
"tid":0,
"ph":"B",
"name":"gamma",
"ts":4,
"args":{
"line":54,
"column":12,
"funcLine":"1",
"funcColumn":"1",
"name":"beta",
"category":"blah",
"parent":1,
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"params":null,
"allocatedCategory":"JavaScript",
"allocatedName":"beta"
}
},
{
"pid":0,
"tid":0,
"ph":"E",
"name":"gamma",
"ts":13,
"args":{
"line":54,
"column":12,
"funcLine":"1",
"funcColumn":"1",
"name":"beta",
"category":"blah",
"parent":1,
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"params":null,
"allocatedCategory":"JavaScript",
"allocatedName":"beta"
}
},
{
"pid":0,
"tid":0,
"ph":"B",
"name":"beta",
"ts":4,
"args":{
"line":54,
"column":12,
"funcLine":"1",
"funcColumn":"1",
"name":"beta",
"category":"blah",
"parent":1,
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"params":null,
"allocatedCategory":"JavaScript",
"allocatedName":"beta"
}
},
{
"pid":0,
"tid":0,
"ph":"E",
"name":"beta",
"ts":10,
"args":{
"line":54,
"column":12,
"funcLine":"1",
"funcColumn":"1",
"name":"beta",
"category":"blah",
"parent":1,
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"params":null,
"allocatedCategory":"JavaScript",
"allocatedName":"beta"
}
},
{
"pid":0,
"tid":0,
"ph":"E",
"name":"[root]",
"ts":14,
"args":{
"name":"[root]",
"category":"root",
"url":null,
"line":null,
"column":null,
"params":null,
"allocatedCategory":"root",
"allocatedName":"[root]"
}
}
]
39 changes: 37 additions & 2 deletions src/import/__snapshots__/trace-event.test.ts.snap
Expand Up @@ -404,6 +404,41 @@ exports[`importTraceEvents event reordering name match: indexToView 1`] = `0`;

exports[`importTraceEvents event reordering name match: profileGroup.name 1`] = `"event-reordering-name-match.json"`;

exports[`importTraceEvents hermes profile with multiple frames 1`] = `
Object {
"frames": Array [
Frame {
"col": null,
"file": null,
"key": "[root]:null:null:null",
"line": null,
"name": "[root]",
"selfWeight": 2,
"totalWeight": 14,
},
Frame {
"col": 12,
"file": "/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"key": "beta:/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js:54:12",
"line": 54,
"name": "beta",
"selfWeight": 12,
"totalWeight": 12,
},
],
"name": "pid 0, tid 0",
"stacks": Array [
"[root] 1.00碌s",
"[root];beta 12.00碌s",
"[root] 1.00碌s",
],
}
`;

exports[`importTraceEvents hermes profile with multiple frames: indexToView 1`] = `0`;

exports[`importTraceEvents hermes profile with multiple frames: profileGroup.name 1`] = `"simple-hermes.json"`;

exports[`importTraceEvents invalid x nesting 1`] = `
Object {
"frames": Array [
Expand Down Expand Up @@ -1321,7 +1356,7 @@ Object {
Frame {
"col": null,
"file": null,
"key": "[root] {\\"name\\":\\"[root]\\",\\"category\\":\\"root\\",\\"url\\":null,\\"line\\":null,\\"column\\":null,\\"params\\":null,\\"allocatedCategory\\":\\"root\\",\\"allocatedName\\":\\"[root]\\"}",
"key": "[root]:null:null:null",
"line": null,
"name": "[root]",
"selfWeight": 2,
Expand All @@ -1330,7 +1365,7 @@ Object {
Frame {
"col": 12,
"file": "/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
"key": "beta {\\"line\\":54,\\"column\\":12,\\"funcLine\\":\\"1\\",\\"funcColumn\\":\\"1\\",\\"name\\":\\"beta\\",\\"category\\":\\"JavaScript\\",\\"parent\\":1,\\"url\\":\\"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js\\",\\"params\\":null,\\"allocatedCategory\\":\\"JavaScript\\",\\"allocatedName\\":\\"beta\\"}",
"key": "beta:/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js:54:12",
"line": 54,
"name": "beta",
"selfWeight": 12,
Expand Down
4 changes: 4 additions & 0 deletions src/import/trace-event.test.ts
Expand Up @@ -127,6 +127,10 @@ test('importTraceEvents simple hermes profile', async () => {
await checkProfileSnapshot('./sample/profiles/trace-event/simple-hermes.json')
})

test('importTraceEvents hermes profile with multiple frames', async () => {
await checkProfileSnapshot('./sample/profiles/trace-event/simple-hermes.json')
})

test('importTraceEvents simple profile with samples', async () => {
await checkProfileSnapshot('./sample/profiles/trace-event/simple-with-samples.json')
})
Expand Down
18 changes: 13 additions & 5 deletions src/import/trace-event.ts
Expand Up @@ -185,7 +185,7 @@ function selectQueueToTakeFromNext(
// to ensure it opens before we try to close it.
//
// Otherwise, process the 'E' queue first.
return keyForEvent(bFront) === keyForEvent(eFront) ? 'B' : 'E'
return getEventId(bFront) === getEventId(eFront) ? 'B' : 'E'
}

function convertToEventQueues(events: ImportableTraceEvent[]): [BTraceEvent[], ETraceEvent[]] {
Expand Down Expand Up @@ -309,7 +309,13 @@ function getEventName(event: TraceEvent): string {
return `${event.name || '(unnamed)'}`
}

function keyForEvent(event: TraceEvent): string {
/**
* Attempt to construct a unique identifier for an event. Note that this
* is different from the frame key, as in some cases we don't want to include
* some arguments to allow from frame grouping (e.g. parent in the case of
* hermes profiles)
*/
function getEventId(event: TraceEvent): string {
let key = getEventName(event)
if (event.args) {
key += ` ${JSON.stringify(event.args)}`
Expand All @@ -321,20 +327,22 @@ function frameInfoForEvent(
event: TraceEvent,
exporterSource: ExporterSource = ExporterSource.UNKNOWN,
): FrameInfo {
const key = keyForEvent(event)

// In Hermes profiles we have additional guaranteed metadata we can use to
// more accurately populate profiles with info such as line + col number
if (exporterSource === ExporterSource.HERMES) {
const hermesFrameKey = `${event.name}:${event.args.url}:${event.args.line}:${event.args.column}`

return {
name: getEventName(event),
key: key,
key: hermesFrameKey,
file: event.args.url,
line: event.args.line,
col: event.args.column,
}
}

const key = getEventId(event)

return {
name: key,
key: key,
Expand Down

0 comments on commit e9a17d5

Please sign in to comment.