mirror of
https://github.com/jlfwong/speedscope.git
synced 2024-11-22 12:53:23 +03:00
Use frame.name?.startsWith
for stackprof (#419)
Sometimes, stackprof frames don't get generated with a `name` in the frame.
I think it's probably worth tracking down why that is, but in the mean
time, speedscope simply crashes with a method call on `undefined`. The
crash is bad because it only shows up in the console--there's no visible
message saying that speedscope failed to parse and load a profile.
For more information, see #378
This fixes the crash by simply skipping the logic in demangle if the name
field isn't present on a frame. That's probably a fine tradeoff? Because in
this case, stackprof is generating ruby frames, which means that C++ name
demangling won't apply.
I have tested this by running the scripts/prepare-test-installation.sh
script and verifying that `bin/cli.js` can now successfully load the
included profile. Before these changes, I verified that speedscope failed
with the behavior mentioned in #378.
I've also included a snapshot test case, but it seems that the Jest test
harness only tests the parsing, not the rendering (correct me if I'm wrong).
So I haven't actually been able to create an automated test that would catch
a regression. Please let me know if there's a better way to have written this
test.
I've staged the commits on this branch so that the second commit (dcb9840
)
showcases the minimal diff to a stackprof file that reproduces the bug. That is,
rather than look at the thousands of new lines in the stackprof profile, you can
view the second commit to see the salient part of the file.
This commit is contained in:
parent
fcc1fa5689
commit
e9133be353
File diff suppressed because one or more lines are too long
@ -1046,6 +1046,201 @@ exports[`importFromStackprof object mode: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromStackprof object mode: profileGroup.name 1`] = `"object-stackprof.json"`;
|
||||
|
||||
exports[`importFromStackprof when a profile has a frame with no name 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "../../alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4317728280,
|
||||
"line": undefined,
|
||||
"name": "<main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4376547240,
|
||||
"line": undefined,
|
||||
"name": "<main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4379035920,
|
||||
"line": null,
|
||||
"name": "StackProf.run",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4317464320,
|
||||
"line": 21,
|
||||
"name": "block in <main>",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4379033920,
|
||||
"line": 4,
|
||||
"name": "Object#a",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 102,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4317869400,
|
||||
"line": null,
|
||||
"name": "Range#each",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 102,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4379033880,
|
||||
"line": 11,
|
||||
"name": "Object#b",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4318054440,
|
||||
"line": null,
|
||||
"name": "Class#new",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4379033840,
|
||||
"line": 15,
|
||||
"name": "Object#c",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 95,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4317868920,
|
||||
"line": null,
|
||||
"name": "Range#to_a",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 37,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4379016640,
|
||||
"line": null,
|
||||
"name": "Enumerable#to_a",
|
||||
"selfWeight": 36,
|
||||
"totalWeight": 36,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<internal:array>",
|
||||
"key": 4317563560,
|
||||
"line": 60,
|
||||
"name": "Array#sample",
|
||||
"selfWeight": 20,
|
||||
"totalWeight": 20,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4317922760,
|
||||
"line": null,
|
||||
"name": "(unknown)",
|
||||
"selfWeight": 36,
|
||||
"totalWeight": 36,
|
||||
},
|
||||
],
|
||||
"name": "stackprof-last-frame-no-name.json",
|
||||
"stacks": Array [
|
||||
"<main>;<main>;StackProf.run;block in <main> 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b;Class#new 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 3",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b;Class#new 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b;Class#new 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromStackprof when a profile has a frame with no name: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromStackprof when a profile has a frame with no name: profileGroup.name 1`] = `"stackprof-last-frame-no-name.json"`;
|
||||
|
||||
exports[`importFromStackprof: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromStackprof: profileGroup.name 1`] = `"simple-stackprof.json"`;
|
||||
|
@ -7,3 +7,7 @@ test('importFromStackprof', async () => {
|
||||
test('importFromStackprof object mode', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackprof/object-stackprof.json')
|
||||
})
|
||||
|
||||
test('importFromStackprof when a profile has a frame with no name', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackprof/stackprof-last-frame-no-name.json')
|
||||
})
|
||||
|
@ -4,7 +4,7 @@ import {Profile, FrameInfo, StackListProfileBuilder} from '../lib/profile'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
|
||||
interface StackprofFrame {
|
||||
name: string
|
||||
name?: string
|
||||
file?: string
|
||||
line?: number
|
||||
}
|
||||
@ -34,10 +34,16 @@ export function importFromStackprof(stackprofProfile: StackprofProfile): Profile
|
||||
let stack: FrameInfo[] = []
|
||||
for (let j = 0; j < stackHeight; j++) {
|
||||
const id = raw[i++]
|
||||
stack.push({
|
||||
let frameName = frames[id].name;
|
||||
if (frameName == null) {
|
||||
frameName = '(unknown)';
|
||||
}
|
||||
const frame = {
|
||||
key: id,
|
||||
...frames[id],
|
||||
})
|
||||
name: frameName,
|
||||
}
|
||||
stack.push(frame)
|
||||
}
|
||||
if (stack.length === 1 && stack[0].name === '(garbage collection)') {
|
||||
stack = prevStack.concat(stack)
|
||||
|
Loading…
Reference in New Issue
Block a user