Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd546ca893 | ||
|
|
0c1e477f35 | ||
|
|
30ca6291ca | ||
|
|
66a9e5d1cf | ||
|
|
a2022a07a2 | ||
|
|
b7806a1c5f | ||
|
|
7f19a13012 | ||
|
|
abd74be9fa | ||
|
|
c706bdfe04 | ||
|
|
cfc8fe8f6e |
@@ -1,5 +1,24 @@
|
||||
## Unreleased
|
||||
|
||||
## [1.5.1] - 2019-06-06
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed import of trace event files which contain unmatched "E" events (#222) (by @jlfwong)
|
||||
|
||||
## [1.5.0] - 2019-02-17
|
||||
|
||||
### Added
|
||||
|
||||
* Support importing unterminated JSON in simple cases (#208) (by @jlfwong)
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix crash when importing from stackpro without raw_timestamp_deltas (#207) (by @jlfwong)
|
||||
* Alert instead of crash when importing a file containing no profiles (#205) (by @jlfwong)
|
||||
* Fixed import of multithreaded profiles from Chrome 66 (#206) (by @jlfwong)
|
||||
* Fixed import of instruments trace files with missing run number (#203) (by @Archerlly)
|
||||
|
||||
## [1.4.1] - 2019-01-22
|
||||
|
||||
### Fixed
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.4.1",
|
||||
"version": "1.5.1",
|
||||
"description": "",
|
||||
"repository": "jlfwong/speedscope",
|
||||
"main": "index.js",
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "beta", "ts": 1},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "gamma", "ts": 2, "dur": 5, "args": {"detail": "foobar"}},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "epsilon", "ts": 7, "tdur": 4},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 13},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 14},
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
[
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "beta", "ts": 1},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "gamma", "ts": 2, "dur": 5, "args": {"detail": "foobar"}},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "epsilon", "ts": 7, "tdur": 4},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 13},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 14},
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "beta", "ts": 1},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "gamma", "ts": 2, "dur": 5, "args": {"detail": "foobar"}},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "epsilon", "ts": 7, "tdur": 4},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 13},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 14}
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "alpha", "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "beta", "ts": 1},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "beta", "ts": 13},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "alpha", "ts": 14},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "gamma", "ts": 5},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "delta", "ts": 5}
|
||||
]
|
||||
@@ -515,6 +515,408 @@ exports[`importFromChromeTimeline Chrome 69: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromChromeTimeline Chrome 69: profileGroup.name 1`] = `"simple.json"`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 66 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "(program)::-1:-1",
|
||||
"line": -1,
|
||||
"name": "(program)",
|
||||
"selfWeight": 819120,
|
||||
"totalWeight": 819120,
|
||||
},
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "http://172.30.3.176:7777/worker.js",
|
||||
"key": "onmessage:http://172.30.3.176:7777/worker.js:14:20",
|
||||
"line": 14,
|
||||
"name": "onmessage",
|
||||
"selfWeight": 639,
|
||||
"totalWeight": 857719,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "http://172.30.3.176:7777/worker.js",
|
||||
"key": "alpha:http://172.30.3.176:7777/worker.js:8:14",
|
||||
"line": 8,
|
||||
"name": "alpha",
|
||||
"selfWeight": 19976,
|
||||
"totalWeight": 835149,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "http://172.30.3.176:7777/worker.js",
|
||||
"key": "gamma:http://172.30.3.176:7777/worker.js:0:14",
|
||||
"line": 0,
|
||||
"name": "gamma",
|
||||
"selfWeight": 22197,
|
||||
"totalWeight": 30000,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "postMessage::-1:-1",
|
||||
"line": -1,
|
||||
"name": "postMessage",
|
||||
"selfWeight": 1278,
|
||||
"totalWeight": 21931,
|
||||
},
|
||||
],
|
||||
"name": "worker.json - DedicatedWorker thread",
|
||||
"stacks": Array [
|
||||
" 9.07ms",
|
||||
"(program) 5.49ms",
|
||||
"onmessage;alpha;gamma 3.69ms",
|
||||
"onmessage;postMessage 212.00µs",
|
||||
"onmessage;postMessage;(program) 3.97ms",
|
||||
"onmessage;alpha;gamma 3.82ms",
|
||||
"onmessage;postMessage 414.00µs",
|
||||
"onmessage;postMessage;(program) 3.71ms",
|
||||
"onmessage;alpha;gamma 1.13ms",
|
||||
"onmessage 188.00µs",
|
||||
"onmessage;alpha;gamma 2.48ms",
|
||||
"onmessage;alpha;gamma;(program) 3.89ms",
|
||||
"onmessage;alpha;gamma 373.00µs",
|
||||
"onmessage;alpha 184.00µs",
|
||||
"onmessage;alpha;gamma 3.36ms",
|
||||
"onmessage;alpha;gamma;(program) 3.91ms",
|
||||
"onmessage;alpha;gamma 3.94ms",
|
||||
"onmessage;postMessage 205.00µs",
|
||||
"onmessage;postMessage;(program) 3.91ms",
|
||||
"onmessage 451.00µs",
|
||||
"onmessage;alpha;gamma 566.00µs",
|
||||
"onmessage;alpha 194.00µs",
|
||||
"onmessage;alpha;gamma 2.09ms",
|
||||
"onmessage;alpha 189.00µs",
|
||||
"onmessage;alpha;gamma 746.00µs",
|
||||
"onmessage;postMessage 211.00µs",
|
||||
"onmessage;postMessage;(program) 4.00ms",
|
||||
"onmessage;alpha 4.80ms",
|
||||
"onmessage;alpha;(program) 5.28ms",
|
||||
"onmessage;alpha 4.70ms",
|
||||
"onmessage;postMessage 236.00µs",
|
||||
"onmessage;postMessage;(program) 5.06ms",
|
||||
"onmessage;alpha 5.07ms",
|
||||
"onmessage;alpha;(program) 4.81ms",
|
||||
"onmessage;alpha 4.84ms",
|
||||
"onmessage;alpha;(program) 775.08ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 66 2`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "(program)::-1:-1",
|
||||
"line": -1,
|
||||
"name": "(program)",
|
||||
"selfWeight": 106601,
|
||||
"totalWeight": 108131,
|
||||
},
|
||||
Frame {
|
||||
"col": 8,
|
||||
"file": "",
|
||||
"key": "(anonymous)::247:8",
|
||||
"line": 247,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 551,
|
||||
"totalWeight": 2766,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "addEventListener::-1:-1",
|
||||
"line": -1,
|
||||
"name": "addEventListener",
|
||||
"selfWeight": 178,
|
||||
"totalWeight": 2215,
|
||||
},
|
||||
Frame {
|
||||
"col": 17,
|
||||
"file": "",
|
||||
"key": "onLoaded::866:17",
|
||||
"line": 866,
|
||||
"name": "onLoaded",
|
||||
"selfWeight": 372,
|
||||
"totalWeight": 5158,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "",
|
||||
"key": "(anonymous)::0:0",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 25649,
|
||||
},
|
||||
Frame {
|
||||
"col": 17,
|
||||
"file": "",
|
||||
"key": "dispatch::845:17",
|
||||
"line": 845,
|
||||
"name": "dispatch",
|
||||
"selfWeight": 1103,
|
||||
"totalWeight": 25649,
|
||||
},
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "",
|
||||
"key": "setPlatform::839:20",
|
||||
"line": 839,
|
||||
"name": "setPlatform",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 902,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "add::-1:-1",
|
||||
"line": -1,
|
||||
"name": "add",
|
||||
"selfWeight": 521,
|
||||
"totalWeight": 902,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "",
|
||||
"key": "reset::433:14",
|
||||
"line": 433,
|
||||
"name": "reset",
|
||||
"selfWeight": 911,
|
||||
"totalWeight": 2438,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "getContext::-1:-1",
|
||||
"line": -1,
|
||||
"name": "getContext",
|
||||
"selfWeight": 598,
|
||||
"totalWeight": 598,
|
||||
},
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "",
|
||||
"key": "resetCanvas::423:20",
|
||||
"line": 423,
|
||||
"name": "resetCanvas",
|
||||
"selfWeight": 370,
|
||||
"totalWeight": 553,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "scale::-1:-1",
|
||||
"line": -1,
|
||||
"name": "scale",
|
||||
"selfWeight": 183,
|
||||
"totalWeight": 183,
|
||||
},
|
||||
Frame {
|
||||
"col": 8,
|
||||
"file": "http://172.30.3.176:7777/worker.html",
|
||||
"key": "(anonymous):http://172.30.3.176:7777/worker.html:0:8",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 2591,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "Worker::-1:-1",
|
||||
"line": -1,
|
||||
"name": "Worker",
|
||||
"selfWeight": 873,
|
||||
"totalWeight": 2591,
|
||||
},
|
||||
Frame {
|
||||
"col": 29,
|
||||
"file": "http://172.30.3.176:7777/worker.html",
|
||||
"key": "worker.onmessage:http://172.30.3.176:7777/worker.html:19:29",
|
||||
"line": 19,
|
||||
"name": "worker.onmessage",
|
||||
"selfWeight": 1221,
|
||||
"totalWeight": 60859,
|
||||
},
|
||||
Frame {
|
||||
"col": 16,
|
||||
"file": "http://172.30.3.176:7777/worker.html",
|
||||
"key": "apple:http://172.30.3.176:7777/worker.html:9:16",
|
||||
"line": 9,
|
||||
"name": "apple",
|
||||
"selfWeight": 5474,
|
||||
"totalWeight": 58863,
|
||||
},
|
||||
Frame {
|
||||
"col": 17,
|
||||
"file": "http://172.30.3.176:7777/worker.html",
|
||||
"key": "banana:http://172.30.3.176:7777/worker.html:1:17",
|
||||
"line": 1,
|
||||
"name": "banana",
|
||||
"selfWeight": 50635,
|
||||
"totalWeight": 53816,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "postMessage::-1:-1",
|
||||
"line": -1,
|
||||
"name": "postMessage",
|
||||
"selfWeight": 348,
|
||||
"totalWeight": 348,
|
||||
},
|
||||
Frame {
|
||||
"col": -1,
|
||||
"file": "",
|
||||
"key": "(garbage collector)::-1:-1",
|
||||
"line": -1,
|
||||
"name": "(garbage collector)",
|
||||
"selfWeight": 1530,
|
||||
"totalWeight": 1530,
|
||||
},
|
||||
],
|
||||
"name": "worker.json - CrRendererMain",
|
||||
"stacks": Array [
|
||||
" 28.66ms",
|
||||
"(program) 315.00µs",
|
||||
" 108.00µs",
|
||||
"(program) 433.00µs",
|
||||
" 116.00µs",
|
||||
"(program) 436.00µs",
|
||||
" 368.00µs",
|
||||
"(program) 108.00µs",
|
||||
" 30.76ms",
|
||||
"(program) 1.48ms",
|
||||
" 167.00µs",
|
||||
"(program) 1.68ms",
|
||||
" 6.96ms",
|
||||
"(program) 2.03ms",
|
||||
" 4.64ms",
|
||||
"(program) 3.86ms",
|
||||
" 14.05ms",
|
||||
"(program) 15.35ms",
|
||||
"(anonymous) 551.00µs",
|
||||
"(anonymous);addEventListener 178.00µs",
|
||||
"(anonymous);addEventListener;(program) 2.04ms",
|
||||
"onLoaded 372.00µs",
|
||||
"onLoaded;(program) 4.79ms",
|
||||
"(anonymous);dispatch;setPlatform;add 521.00µs",
|
||||
"(anonymous);dispatch;setPlatform;add;(program) 381.00µs",
|
||||
"(anonymous);dispatch 927.00µs",
|
||||
"(anonymous);dispatch;reset 185.00µs",
|
||||
"(anonymous);dispatch;reset;getContext 598.00µs",
|
||||
"(anonymous);dispatch;reset 131.00µs",
|
||||
"(anonymous);dispatch;reset;resetCanvas 370.00µs",
|
||||
"(anonymous);dispatch;reset;resetCanvas;scale 183.00µs",
|
||||
"(anonymous);dispatch;reset 595.00µs",
|
||||
"(anonymous);dispatch;reset;(program) 376.00µs",
|
||||
"(anonymous);dispatch 176.00µs",
|
||||
"(anonymous);dispatch;(program) 21.21ms",
|
||||
" 606.00µs",
|
||||
"(program) 11.20ms",
|
||||
" 296.00µs",
|
||||
"(program) 1.90ms",
|
||||
"(anonymous);Worker 873.00µs",
|
||||
"(anonymous);Worker;(program) 1.72ms",
|
||||
" 670.00µs",
|
||||
"(program) 28.45ms",
|
||||
" 353.00µs",
|
||||
"(program) 187.00µs",
|
||||
" 185.00µs",
|
||||
"(program) 4.29ms",
|
||||
" 607.00µs",
|
||||
"(program) 192.00µs",
|
||||
" 407.00µs",
|
||||
"(program) 215.00µs",
|
||||
" 28.98ms",
|
||||
"(program) 770.00µs",
|
||||
"worker.onmessage;apple 185.00µs",
|
||||
"worker.onmessage;apple;banana 180.00µs",
|
||||
"worker.onmessage;apple 367.00µs",
|
||||
"worker.onmessage;apple;banana 182.00µs",
|
||||
"worker.onmessage;apple 183.00µs",
|
||||
"worker.onmessage;apple;banana 546.00µs",
|
||||
"worker.onmessage;apple 365.00µs",
|
||||
"worker.onmessage;apple;banana 182.00µs",
|
||||
"worker.onmessage;apple 365.00µs",
|
||||
"worker.onmessage;apple;banana 188.00µs",
|
||||
"worker.onmessage;apple 912.00µs",
|
||||
"worker.onmessage;apple;banana 189.00µs",
|
||||
"worker.onmessage;apple 2.51ms",
|
||||
"worker.onmessage;apple;banana 8.48ms",
|
||||
"worker.onmessage;postMessage 170.00µs",
|
||||
" 3.95ms",
|
||||
"worker.onmessage;apple;banana 433.00µs",
|
||||
"worker.onmessage 187.00µs",
|
||||
"worker.onmessage;apple;banana 3.30ms",
|
||||
" 3.90ms",
|
||||
"(program) 187.00µs",
|
||||
"worker.onmessage;apple;banana 1.47ms",
|
||||
"worker.onmessage;apple 187.00µs",
|
||||
"worker.onmessage;apple;banana 2.05ms",
|
||||
" 4.01ms",
|
||||
"worker.onmessage;apple;banana 3.77ms",
|
||||
"worker.onmessage;postMessage 178.00µs",
|
||||
" 3.87ms",
|
||||
"worker.onmessage;apple;banana 3.74ms",
|
||||
"worker.onmessage 233.00µs",
|
||||
" 3.88ms",
|
||||
"(program) 187.00µs",
|
||||
"worker.onmessage;apple;banana 744.00µs",
|
||||
"worker.onmessage;apple 196.00µs",
|
||||
"worker.onmessage;apple;banana 2.08ms",
|
||||
"worker.onmessage 188.00µs",
|
||||
"worker.onmessage;apple;banana 582.00µs",
|
||||
" 4.46ms",
|
||||
"(program) 187.00µs",
|
||||
"worker.onmessage;apple;banana 3.84ms",
|
||||
"worker.onmessage;apple;banana;(program) 278.00µs",
|
||||
" 4.76ms",
|
||||
"worker.onmessage;apple;banana 5.01ms",
|
||||
"worker.onmessage;apple;banana;(program) 214.00µs",
|
||||
" 4.67ms",
|
||||
"(program) 193.00µs",
|
||||
"worker.onmessage;apple;banana 2.44ms",
|
||||
"worker.onmessage 186.00µs",
|
||||
"worker.onmessage;apple;banana 1.02ms",
|
||||
"worker.onmessage;banana 209.00µs",
|
||||
"worker.onmessage;apple;banana 207.00µs",
|
||||
"worker.onmessage;apple 207.00µs",
|
||||
"worker.onmessage;apple;banana 634.00µs",
|
||||
"worker.onmessage;apple;banana;(program) 237.00µs",
|
||||
" 4.92ms",
|
||||
"worker.onmessage;apple;banana 3.05ms",
|
||||
"worker.onmessage;banana 218.00µs",
|
||||
"worker.onmessage;apple;banana 876.00µs",
|
||||
"worker.onmessage 219.00µs",
|
||||
"worker.onmessage;apple;banana 219.00µs",
|
||||
"worker.onmessage;apple;banana;(program) 706.00µs",
|
||||
" 4.40ms",
|
||||
"worker.onmessage;apple;banana 2.71ms",
|
||||
"worker.onmessage 208.00µs",
|
||||
"worker.onmessage;apple;banana 2.08ms",
|
||||
"worker.onmessage;apple;banana;(program) 216.00µs",
|
||||
"worker.onmessage;apple;banana;(program);(garbage collector) 1.53ms",
|
||||
" 469.53ms",
|
||||
"(program) 382.00µs",
|
||||
" 262.13ms",
|
||||
"(program) 200.00µs",
|
||||
" 4.51ms",
|
||||
"(program) 221.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 66: indexToView 1`] = `1`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 66: profileGroup.name 1`] = `"worker.json"`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 70 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,40 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importTraceEvents bad E events 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "alpha",
|
||||
"line": undefined,
|
||||
"name": "alpha",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "beta",
|
||||
"line": undefined,
|
||||
"name": "beta",
|
||||
"selfWeight": 12,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"alpha 1.00µs",
|
||||
"alpha;beta 12.00µs",
|
||||
"alpha 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents bad E events: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents bad E events: profileGroup.name 1`] = `"too-many-end-events.json"`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -164,6 +199,174 @@ exports[`importTraceEvents multiprocess: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents multiprocess: profileGroup.name 1`] = `"multiprocess.json"`;
|
||||
|
||||
exports[`importTraceEvents partial json import 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "alpha",
|
||||
"line": undefined,
|
||||
"name": "alpha",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "beta",
|
||||
"line": undefined,
|
||||
"name": "beta",
|
||||
"selfWeight": 3,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "gamma {\\"detail\\":\\"foobar\\"}",
|
||||
"line": undefined,
|
||||
"name": "gamma {\\"detail\\":\\"foobar\\"}",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "epsilon",
|
||||
"line": undefined,
|
||||
"name": "epsilon",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"alpha 1.00µs",
|
||||
"alpha;beta 1.00µs",
|
||||
"alpha;beta;gamma {\\"detail\\":\\"foobar\\"} 5.00µs",
|
||||
"alpha;beta;epsilon 4.00µs",
|
||||
"alpha;beta 2.00µs",
|
||||
"alpha 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents partial json import trailing comma 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "alpha",
|
||||
"line": undefined,
|
||||
"name": "alpha",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "beta",
|
||||
"line": undefined,
|
||||
"name": "beta",
|
||||
"selfWeight": 3,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "gamma {\\"detail\\":\\"foobar\\"}",
|
||||
"line": undefined,
|
||||
"name": "gamma {\\"detail\\":\\"foobar\\"}",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "epsilon",
|
||||
"line": undefined,
|
||||
"name": "epsilon",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"alpha 1.00µs",
|
||||
"alpha;beta 1.00µs",
|
||||
"alpha;beta;gamma {\\"detail\\":\\"foobar\\"} 5.00µs",
|
||||
"alpha;beta;epsilon 4.00µs",
|
||||
"alpha;beta 2.00µs",
|
||||
"alpha 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents partial json import trailing comma: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents partial json import trailing comma: profileGroup.name 1`] = `"simple-partial-trailing-comma.json"`;
|
||||
|
||||
exports[`importTraceEvents partial json import whitespace padding 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "alpha",
|
||||
"line": undefined,
|
||||
"name": "alpha",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "beta",
|
||||
"line": undefined,
|
||||
"name": "beta",
|
||||
"selfWeight": 3,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "gamma {\\"detail\\":\\"foobar\\"}",
|
||||
"line": undefined,
|
||||
"name": "gamma {\\"detail\\":\\"foobar\\"}",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "epsilon",
|
||||
"line": undefined,
|
||||
"name": "epsilon",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"alpha 1.00µs",
|
||||
"alpha;beta 1.00µs",
|
||||
"alpha;beta;gamma {\\"detail\\":\\"foobar\\"} 5.00µs",
|
||||
"alpha;beta;epsilon 4.00µs",
|
||||
"alpha;beta 2.00µs",
|
||||
"alpha 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents partial json import whitespace padding: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents partial json import whitespace padding: profileGroup.name 1`] = `"simple-partial-whitespace.json"`;
|
||||
|
||||
exports[`importTraceEvents partial json import: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents partial json import: profileGroup.name 1`] = `"simple-partial.json"`;
|
||||
|
||||
exports[`importTraceEvents simple 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
|
||||
@@ -16,6 +16,10 @@ test('importFromV8Profiler Node 10', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/node/10.11.0/example.cpuprofile')
|
||||
})
|
||||
|
||||
test('importFromChromeTimeline Workers Chrome 66', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Chrome/66/worker.json')
|
||||
})
|
||||
|
||||
test('importFromChromeTimeline Workers Chrome 70', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Chrome/70/worker.json')
|
||||
})
|
||||
|
||||
+9
-12
@@ -79,19 +79,17 @@ export function importFromChromeTimeline(events: TimelineEvent[], fileName: stri
|
||||
// that they are.
|
||||
sortBy(events, e => e.ts)
|
||||
|
||||
const DEFAULT_ID = '(default id)'
|
||||
|
||||
for (let event of events) {
|
||||
if (event.name === 'CpuProfile') {
|
||||
cpuProfileByID.set(event.id || DEFAULT_ID, event.args.data.cpuProfile as CPUProfile)
|
||||
|
||||
if (event.id) {
|
||||
pidTidById.set(event.id, `${event.pid}:${event.tid}`)
|
||||
}
|
||||
const pidTid = `${event.pid}:${event.tid}`
|
||||
const id = event.id || pidTid
|
||||
cpuProfileByID.set(id, event.args.data.cpuProfile as CPUProfile)
|
||||
pidTidById.set(id, pidTid)
|
||||
}
|
||||
|
||||
if (event.name === 'Profile') {
|
||||
cpuProfileByID.set(event.id || DEFAULT_ID, {
|
||||
const pidTid = `${event.pid}:${event.tid}`
|
||||
cpuProfileByID.set(event.id || pidTid, {
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
nodes: [],
|
||||
@@ -110,7 +108,8 @@ export function importFromChromeTimeline(events: TimelineEvent[], fileName: stri
|
||||
}
|
||||
|
||||
if (event.name === 'ProfileChunk') {
|
||||
const cpuProfile = cpuProfileByID.get(event.id || DEFAULT_ID)
|
||||
const pidTid = `${event.pid}:${event.tid}`
|
||||
const cpuProfile = cpuProfileByID.get(event.id || pidTid)
|
||||
if (cpuProfile) {
|
||||
const chunk = event.args.data
|
||||
if (chunk.cpuProfile) {
|
||||
@@ -131,9 +130,7 @@ export function importFromChromeTimeline(events: TimelineEvent[], fileName: stri
|
||||
cpuProfile.endTime = chunk.endTime
|
||||
}
|
||||
} else {
|
||||
console.warn(
|
||||
`Ignoring ProfileChunk for undeclared Profile with id ${event.id || DEFAULT_ID}`,
|
||||
)
|
||||
console.warn(`Ignoring ProfileChunk for undeclared Profile with id ${event.id || pidTid}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,8 @@ test('importProfileGroup', async () => {
|
||||
expect(await importProfileGroupFromText('unknown', '')).toBe(null)
|
||||
expect(await importProfileGroupFromText('unknown', 'Hello world')).toBe(null)
|
||||
expect(await importProfileGroupFromText('unknown', 'Hello\n\nWorld')).toBe(null)
|
||||
|
||||
// Importing from a version of stackprof which was missing raw_timestamp_deltas should return null
|
||||
const oldStackprof = `{"version":1.2,"mode":"wall","interval":1000,"samples":0,"gc_samples":0,"missed_samples":0,"frames":{}}`
|
||||
expect(await importProfileGroupFromText('unknown', oldStackprof)).toBe(null)
|
||||
})
|
||||
|
||||
+22
-2
@@ -71,6 +71,26 @@ function toGroup(profile: Profile | null): ProfileGroup | null {
|
||||
return {name: profile.getName(), indexToView: 0, profiles: [profile]}
|
||||
}
|
||||
|
||||
function fixUpJSON(content: string): string {
|
||||
// This code is similar to the code from here:
|
||||
// https://github.com/catapult-project/catapult/blob/27e047e0494df162022be6aa8a8862742a270232/tracing/tracing/extras/importer/trace_event_importer.html#L197-L208
|
||||
//
|
||||
// If the event data begins with a [, then we know it should end with a ]. The
|
||||
// reason we check for this is because some tracing implementations cannot
|
||||
// guarantee that a ']' gets written to the trace file. So, we are forgiving
|
||||
// and if this is obviously the case, we fix it up before throwing the string
|
||||
// at JSON.parse.
|
||||
//
|
||||
content = content.trim()
|
||||
if (content[0] === '[') {
|
||||
content = content.replace(/,\s*$/, '')
|
||||
if (content[content.length - 1] !== ']') {
|
||||
content += ']'
|
||||
}
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
async function _importProfileGroup(dataSource: ProfileDataSource): Promise<ProfileGroup | null> {
|
||||
const fileName = await dataSource.name()
|
||||
|
||||
@@ -116,7 +136,7 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
// Second pass: Try to guess what file format it is based on structure
|
||||
let parsed: any
|
||||
try {
|
||||
parsed = JSON.parse(contents)
|
||||
parsed = JSON.parse(fixUpJSON(contents))
|
||||
} catch (e) {}
|
||||
if (parsed) {
|
||||
if (parsed['$schema'] === 'https://www.speedscope.app/file-format-schema.json') {
|
||||
@@ -137,7 +157,7 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
} else if ('head' in parsed && 'samples' in parsed && 'timestamps' in parsed) {
|
||||
console.log('Importing as Chrome CPU Profile (old format)')
|
||||
return toGroup(importFromOldV8CPUProfile(parsed))
|
||||
} else if ('mode' in parsed && 'frames' in parsed) {
|
||||
} else if ('mode' in parsed && 'frames' in parsed && 'raw_timestamp_deltas' in parsed) {
|
||||
console.log('Importing as stackprof profile')
|
||||
return toGroup(importFromStackprof(parsed))
|
||||
} else if ('code' in parsed && 'functions' in parsed && 'ticks' in parsed) {
|
||||
|
||||
@@ -98,4 +98,7 @@ describe('importFromInstrumentsTrace', () => {
|
||||
test('Instruments 9.3.1', async () => {
|
||||
await importFromTrace('./sample/profiles/Instruments/9.3.1/simple-time-profile.trace.zip')
|
||||
})
|
||||
test('Instruments 10.0', async () => {
|
||||
await importFromTrace('./sample/profiles/Instruments/10.0/simple-time-profile.trace.zip')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -361,7 +361,10 @@ async function readFormTemplate(tree: TraceDirectoryTree): Promise<FormTemplateD
|
||||
const archive = readInstrumentsKeyedArchive(await readAsArrayBuffer(formTemplate))
|
||||
|
||||
const version = archive['com.apple.xray.owner.template.version']
|
||||
const selectedRunNumber = archive['com.apple.xray.owner.template'].get('_selectedRunNumber')
|
||||
let selectedRunNumber = 1
|
||||
if ('com.apple.xray.owner.template' in archive) {
|
||||
selectedRunNumber = archive['com.apple.xray.owner.template'].get('_selectedRunNumber')
|
||||
}
|
||||
let instrument = archive['$1']
|
||||
if ('stubInfoByUUID' in archive) {
|
||||
instrument = Array.from(archive['stubInfoByUUID'].keys())[0]
|
||||
|
||||
@@ -11,3 +11,19 @@ test('importTraceEvents simple object', async () => {
|
||||
test('importTraceEvents multiprocess', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/multiprocess.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents partial json import', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-partial.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents partial json import trailing comma', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-partial-trailing-comma.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents partial json import whitespace padding', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-partial-whitespace.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents bad E events', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/too-many-end-events.json')
|
||||
})
|
||||
|
||||
+28
-17
@@ -1,4 +1,4 @@
|
||||
import {sortBy, zeroPad} from '../lib/utils'
|
||||
import {sortBy, zeroPad, lastOf} from '../lib/utils'
|
||||
import {ProfileGroup, CallTreeProfileBuilder, FrameInfo} from '../lib/profile'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
|
||||
@@ -143,8 +143,10 @@ function keyForEvent(event: TraceEvent): string {
|
||||
return name
|
||||
}
|
||||
|
||||
type TraceEventProfileState = {profile: CallTreeProfileBuilder; eventStack: BTraceEvent[]}
|
||||
|
||||
function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
const profileByPidTid = new Map<string, CallTreeProfileBuilder>()
|
||||
const stateByPidTid = new Map<string, TraceEventProfileState>()
|
||||
|
||||
const importableEvents = filterIgnoredEventTypes(events)
|
||||
const durationEvents = convertToDurationEvents(importableEvents)
|
||||
@@ -185,15 +187,16 @@ function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
}
|
||||
}
|
||||
|
||||
function getOrCreateProfile(pid: number, tid: number) {
|
||||
function getOrCreateProfileState(pid: number, tid: number): TraceEventProfileState {
|
||||
// We zero-pad the PID and TID to make sorting them by pid/tid pair later easier.
|
||||
const pidTid = `${zeroPad('' + pid, 10)}:${zeroPad('' + tid, 10)}`
|
||||
|
||||
let profile = profileByPidTid.get(pidTid)
|
||||
if (profile != null) return profile
|
||||
profile = new CallTreeProfileBuilder()
|
||||
let state = stateByPidTid.get(pidTid)
|
||||
if (state != null) return state
|
||||
let profile = new CallTreeProfileBuilder()
|
||||
state = {profile, eventStack: []}
|
||||
profile.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
profileByPidTid.set(pidTid, profile)
|
||||
stateByPidTid.set(pidTid, state)
|
||||
|
||||
const processName = processNamesByPid.get(pid)
|
||||
const threadName = threadNamesByPidTid.get(`${pid}:${tid}`)
|
||||
@@ -208,11 +211,11 @@ function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
profile.setName(`pid ${pid}, tid ${tid}`)
|
||||
}
|
||||
|
||||
return profile
|
||||
return state
|
||||
}
|
||||
|
||||
for (let ev of durationEvents) {
|
||||
const profile = getOrCreateProfile(ev.pid, ev.tid)
|
||||
const {profile, eventStack} = getOrCreateProfileState(ev.pid, ev.tid)
|
||||
const key = keyForEvent(ev)
|
||||
const frameInfo: FrameInfo = {
|
||||
key: key,
|
||||
@@ -220,11 +223,23 @@ function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
}
|
||||
switch (ev.ph) {
|
||||
case 'B':
|
||||
eventStack.push(ev)
|
||||
profile.enterFrame(frameInfo, ev.ts)
|
||||
break
|
||||
|
||||
case 'E':
|
||||
profile.leaveFrame(frameInfo, ev.ts)
|
||||
const lastEvent = lastOf(eventStack)
|
||||
if (lastEvent != null && lastEvent.name === ev.name) {
|
||||
profile.leaveFrame(frameInfo, ev.ts)
|
||||
eventStack.pop()
|
||||
} else {
|
||||
console.warn(
|
||||
'Event discarded because it did not match top-of-stack. Discarded event:',
|
||||
ev,
|
||||
'Top of stack:',
|
||||
lastEvent,
|
||||
)
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
@@ -237,10 +252,10 @@ function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
// TODO: The standard specifies that metadata events with the name
|
||||
// "process_sort_index" and "thread_sort_index" can be used to influence the
|
||||
// order, but for simplicity we'll ignore that until someone complains :)
|
||||
const profilePairs = Array.from(profileByPidTid.entries())
|
||||
const profilePairs = Array.from(stateByPidTid.entries())
|
||||
sortBy(profilePairs, p => p[0])
|
||||
|
||||
return {name: '', indexToView: 0, profiles: profilePairs.map(p => p[1])}
|
||||
return {name: '', indexToView: 0, profiles: profilePairs.map(p => p[1].profile)}
|
||||
}
|
||||
|
||||
function isTraceEventList(maybeEventList: any): maybeEventList is TraceEvent[] {
|
||||
@@ -285,13 +300,9 @@ function isTraceEventObject(
|
||||
export function isTraceEventFormatted(
|
||||
rawProfile: any,
|
||||
): rawProfile is {traceEvents: TraceEvent[]} | TraceEvent[] {
|
||||
// We're only going to suppor the JSON formatted profiles for now.
|
||||
// We're only going to support the JSON formatted profiles for now.
|
||||
// The spec also discusses support for data embedded in ftrace supported data: https://lwn.net/Articles/365835/.
|
||||
|
||||
// TODO(jlfwong): The spec also specifies that it's valid for the trace to not contain a terminating `]`.
|
||||
// That complicates things a bit for us, so let's just ignore that for now until someone writes in with a
|
||||
// bug report from real data.
|
||||
|
||||
return isTraceEventObject(rawProfile) || isTraceEventList(rawProfile)
|
||||
}
|
||||
|
||||
|
||||
@@ -310,11 +310,15 @@ export class Application extends StatelessComponent<ApplicationProps> {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(jlfwong): Make these into nicer overlays
|
||||
if (profileGroup == null) {
|
||||
// TODO(jlfwong): Make this a nicer overlay
|
||||
alert('Unrecognized format! See documentation about supported formats.')
|
||||
this.props.setLoading(false)
|
||||
return
|
||||
} else if (profileGroup.profiles.length === 0) {
|
||||
alert("Successfully imported profile, but it's empty!")
|
||||
this.props.setLoading(false)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.props.hashParams.title) {
|
||||
|
||||
Reference in New Issue
Block a user