Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7cca1a76bc | ||
|
|
8c574d1c92 | ||
|
|
fbc8946caa | ||
|
|
8cddf3fe81 | ||
|
|
c15ca263d3 | ||
|
|
519847b489 | ||
|
|
6d4f3499da | ||
|
|
ad49dacb29 | ||
|
|
6562fec7a7 |
@@ -1,5 +1,24 @@
|
||||
## Unreleased
|
||||
|
||||
## [1.4.0] - 2019-01-22
|
||||
|
||||
### Added
|
||||
|
||||
* Import v8 cpu profile (old format) [#177] (by @vmarchaud)
|
||||
* Import basic "Trace Event Format" profiles [#197] (by @jlfwong)
|
||||
|
||||
## [1.3.2] - 2018-12-03
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed import of multithreaded Chrome profiles [#19] (by @jlfwong)
|
||||
|
||||
## [1.3.1] - 2018-11-08
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fixed a file import performance regression by using TextDecoder [#188] (by @jlfwong)
|
||||
|
||||
## [1.3.0] - 2018-10-29
|
||||
|
||||
### Added
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.3.0",
|
||||
"version": "1.4.0",
|
||||
"description": "",
|
||||
"repository": "jlfwong/speedscope",
|
||||
"main": "index.js",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
{"head":{"functionName":"(root)","url":"","lineNumber":-1,"bailoutReason":"","id":1,"scriptId":0,"hitCount":0,"children":[{"functionName":"","url":"","lineNumber":0,"callUID":1,"bailoutReason":"","id":2,"scriptId":0,"hitCount":0,"children":[{"functionName":"a","url":"","lineNumber":0,"callUID":2,"bailoutReason":"","id":3,"scriptId":0,"hitCount":0,"children":[{"functionName":"b","url":"","lineNumber":5,"callUID":3,"bailoutReason":"","id":4,"scriptId":0,"hitCount":0,"children":[{"functionName":"d","url":"","lineNumber":13,"callUID":4,"bailoutReason":"","id":5,"scriptId":0,"hitCount":14,"children":[]}]},{"functionName":"c","url":"","lineNumber":9,"callUID":3,"bailoutReason":"","id":6,"scriptId":0,"hitCount":0,"children":[{"functionName":"d","url":"","lineNumber":13,"callUID":6,"bailoutReason":"","id":7,"scriptId":0,"hitCount":14,"children":[]}]}]}]}]},"startTime":163140,"endTime":163140,"samples":[2,5,5,5,5,5,5,5,5,5,5,5,5,5,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7],"timestamps":[163140599286,163140610861,163140611921,163140612966,163140614236,163140615507,163140616694,163140617968,163140619238,163140620258,163140621507,163140622765,163140624037,163140625303,163140626378,163140627649,163140628923,163140630191,163140631457,163140632746,163140634032,163140635304,163140636440,163140637716,163140638990,163140640255,163140641520,163140642791,163140644063,163140645206]}
|
||||
@@ -0,0 +1,22 @@
|
||||
[
|
||||
{"pid": 0, "tid": 0, "ph": "M", "name": "process_name", "args": {"name": "p0"}, "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "M", "name": "thread_name", "args": {"name": "p0t0"}, "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "X", "name": "alpha", "ts": 0, "dur": 1},
|
||||
{"pid": 0, "tid": 1, "ph": "M", "name": "thread_name", "args": {"name": "p0t1"}, "ts": 0},
|
||||
{"pid": 0, "tid": 1, "ph": "X", "name": "beta", "ts": 0, "dur": 1},
|
||||
|
||||
{"pid": 1, "tid": 0, "ph": "M", "name": "process_name", "args": {"name": "p1"}, "ts": 0},
|
||||
{"pid": 1, "tid": 0, "ph": "M", "name": "thread_name", "args": {"name": "p1t0"}, "ts": 0},
|
||||
{"pid": 1, "tid": 0, "ph": "X", "name": "gamma", "ts": 0, "dur": 1},
|
||||
{"pid": 1, "tid": 1, "ph": "M", "name": "thread_name", "args": {"name": "p1t1"}, "ts": 0},
|
||||
{"pid": 1, "tid": 1, "ph": "X", "name": "delta", "ts": 0, "dur": 1},
|
||||
|
||||
{"pid": 2, "tid": 0, "ph": "M", "name": "thread_name", "args": {"name": "p2t0"}, "ts": 0},
|
||||
{"pid": 2, "tid": 0, "ph": "X", "name": "epsilon", "ts": 0, "dur": 1},
|
||||
{"pid": 2, "tid": 1, "ph": "M", "name": "thread_name", "args": {"name": "p2t1"}, "ts": 0},
|
||||
{"pid": 2, "tid": 1, "ph": "X", "name": "phi", "ts": 0, "dur": 1},
|
||||
|
||||
{"pid": 3, "tid": 0, "ph": "M", "name": "process_name", "args": {"name": "p3"}, "ts": 0},
|
||||
{"pid": 3, "tid": 0, "ph": "X", "name": "zeta", "ts": 0, "dur": 1},
|
||||
{"pid": 3, "tid": 1, "ph": "X", "name": "eta", "ts": 0, "dur": 1}
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"traceEvents": [
|
||||
{"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", "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": "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,60 @@
|
||||
/*
|
||||
* This script is used to reconstruct an cpu profile from chrome with an old format
|
||||
* still used in nodejs with v8-profiler
|
||||
*/
|
||||
const fs = require('fs')
|
||||
|
||||
const data = JSON.parse(fs.readFileSync('../../profiles/Chrome/65/simple.cpuprofile').toString())
|
||||
|
||||
const _convertTimeDeltas = (profile) => {
|
||||
if (!profile.timeDeltas) return null
|
||||
let lastTimeUsec = profile.startTime
|
||||
const timestamps = new Array(profile.timeDeltas.length + 1)
|
||||
for (let i = 0; i < profile.timeDeltas.length; ++i) {
|
||||
timestamps[i] = lastTimeUsec
|
||||
lastTimeUsec += profile.timeDeltas[i]
|
||||
}
|
||||
timestamps[profile.timeDeltas.length] = lastTimeUsec
|
||||
return timestamps
|
||||
}
|
||||
|
||||
const reformatNode = node => {
|
||||
if (!node.children) node.children = []
|
||||
|
||||
node.children = node.children.map(childID => {
|
||||
if (typeof childID !== 'number') return childID
|
||||
const childNode = data.nodes.find(node => node.id === childID)
|
||||
if (typeof childNode !== 'object') return null
|
||||
childNode.callUID = node.id
|
||||
return childNode
|
||||
})
|
||||
return {
|
||||
functionName: node.callFrame.functionName,
|
||||
url: node.callFrame.url,
|
||||
lineNumber: node.callFrame.lineNumber,
|
||||
callUID: node.callUID,
|
||||
bailoutReason: '',
|
||||
id: node.id,
|
||||
scriptId: 0,
|
||||
hitCount: node.hitCount,
|
||||
children: node.children.map(reformatNode)
|
||||
}
|
||||
}
|
||||
|
||||
// reformat then only keep the root as top level node
|
||||
const nodes = data.nodes
|
||||
.map(reformatNode)
|
||||
.filter(node => node.functionName === '(root)')[0]
|
||||
|
||||
// since it can be undefined, create an array so execution still works
|
||||
if (!data.timeDeltas) {
|
||||
data.timeDeltas = []
|
||||
}
|
||||
|
||||
fs.writeFileSync('./new.cpuprofile', JSON.stringify({
|
||||
head: nodes,
|
||||
startTime: Math.floor(data.startTime / 1000000),
|
||||
endTime: Math.floor(data.endTime / 1000000),
|
||||
samples: data.samples,
|
||||
timestamps: _convertTimeDeltas(data)
|
||||
}))
|
||||
@@ -0,0 +1,28 @@
|
||||
<script>
|
||||
function banana() {
|
||||
let prod = 1
|
||||
for (let i = 1; i < 1000; i++) {
|
||||
prod *= i
|
||||
}
|
||||
return prod
|
||||
}
|
||||
|
||||
function apple() {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
banana()
|
||||
}
|
||||
}
|
||||
|
||||
let bounces = 0
|
||||
|
||||
const worker = new Worker('./worker.js')
|
||||
|
||||
worker.onmessage = function() {
|
||||
apple()
|
||||
if (bounces++ < 10) {
|
||||
worker.postMessage('ping')
|
||||
}
|
||||
}
|
||||
|
||||
worker.postMessage('ping')
|
||||
</script>
|
||||
@@ -0,0 +1,18 @@
|
||||
function gamma() {
|
||||
let prod = 1
|
||||
for (let i = 1; i < 1000; i++) {
|
||||
prod *= i
|
||||
}
|
||||
return prod
|
||||
}
|
||||
|
||||
function alpha() {
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
gamma()
|
||||
}
|
||||
}
|
||||
|
||||
onmessage = function(e) {
|
||||
alpha()
|
||||
postMessage('pong')
|
||||
}
|
||||
@@ -515,6 +515,908 @@ exports[`importFromChromeTimeline Chrome 69: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromChromeTimeline Chrome 69: profileGroup.name 1`] = `"simple.json"`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 70 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "(anonymous):extensions::SafeBuiltins:0:0",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 37463,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "(anonymous):extensions::SafeBuiltins:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 37463,
|
||||
},
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "saveBuiltin:extensions::SafeBuiltins:24:20",
|
||||
"line": 24,
|
||||
"name": "saveBuiltin",
|
||||
"selfWeight": 233,
|
||||
"totalWeight": 9858,
|
||||
},
|
||||
Frame {
|
||||
"col": 21,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "makeCallable:extensions::SafeBuiltins:6:21",
|
||||
"line": 6,
|
||||
"name": "makeCallable",
|
||||
"selfWeight": 122,
|
||||
"totalWeight": 7007,
|
||||
},
|
||||
Frame {
|
||||
"col": 32,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "(anonymous):extensions::SafeBuiltins:7:32",
|
||||
"line": 7,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 234,
|
||||
"totalWeight": 234,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "(program):undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "(program)",
|
||||
"selfWeight": 48725,
|
||||
"totalWeight": 48827,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "(garbage collector):undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "(garbage collector)",
|
||||
"selfWeight": 3380,
|
||||
"totalWeight": 3380,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "(anonymous):chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:0:0",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 1550,
|
||||
"totalWeight": 15220,
|
||||
},
|
||||
Frame {
|
||||
"col": 466,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "La:chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:34:466",
|
||||
"line": 34,
|
||||
"name": "La",
|
||||
"selfWeight": 407,
|
||||
"totalWeight": 11272,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "get webstore:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "get webstore",
|
||||
"selfWeight": 287,
|
||||
"totalWeight": 15564,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::runtime",
|
||||
"key": "(anonymous):extensions::runtime:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 2319,
|
||||
"totalWeight": 15277,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "privates:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "privates",
|
||||
"selfWeight": 1751,
|
||||
"totalWeight": 6636,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::binding",
|
||||
"key": "(anonymous):extensions::binding:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 791,
|
||||
"totalWeight": 4994,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::event_bindings",
|
||||
"key": "(anonymous):extensions::event_bindings:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 822,
|
||||
"totalWeight": 4068,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::sendRequest",
|
||||
"key": "(anonymous):extensions::sendRequest:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 761,
|
||||
"totalWeight": 2844,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::schemaUtils",
|
||||
"key": "(anonymous):extensions::schemaUtils:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 847,
|
||||
"totalWeight": 1814,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::json_schema",
|
||||
"key": "(anonymous):extensions::json_schema:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 834,
|
||||
"totalWeight": 834,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "extensions::utils",
|
||||
"key": "expose:extensions::utils:97:15",
|
||||
"line": 97,
|
||||
"name": "expose",
|
||||
"selfWeight": 147,
|
||||
"totalWeight": 293,
|
||||
},
|
||||
Frame {
|
||||
"col": 35,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "target.(anonymous function):extensions::SafeBuiltins:9:35",
|
||||
"line": 9,
|
||||
"name": "target.(anonymous function)",
|
||||
"selfWeight": 727,
|
||||
"totalWeight": 7136,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "Apply:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "Apply",
|
||||
"selfWeight": 2187,
|
||||
"totalWeight": 6547,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::messaging",
|
||||
"key": "(anonymous):extensions::messaging:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 151,
|
||||
"totalWeight": 428,
|
||||
},
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "extensions::binding",
|
||||
"key": "generate:extensions::binding:198:20",
|
||||
"line": 198,
|
||||
"name": "generate",
|
||||
"selfWeight": 149,
|
||||
"totalWeight": 7002,
|
||||
},
|
||||
Frame {
|
||||
"col": 36,
|
||||
"file": "extensions::binding",
|
||||
"key": "shouldCheckUnprivileged:extensions::binding:208:36",
|
||||
"line": 208,
|
||||
"name": "shouldCheckUnprivileged",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 146,
|
||||
},
|
||||
Frame {
|
||||
"col": 43,
|
||||
"file": "extensions::binding",
|
||||
"key": "(anonymous):extensions::binding:252:43",
|
||||
"line": 252,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3651,
|
||||
},
|
||||
Frame {
|
||||
"col": 49,
|
||||
"file": "extensions::json_schema",
|
||||
"key": "JSONSchemaValidator.addTypes:extensions::json_schema:173:49",
|
||||
"line": 173,
|
||||
"name": "JSONSchemaValidator.addTypes",
|
||||
"selfWeight": 149,
|
||||
"totalWeight": 149,
|
||||
},
|
||||
Frame {
|
||||
"col": 45,
|
||||
"file": "extensions::binding",
|
||||
"key": "(anonymous):extensions::binding:270:45",
|
||||
"line": 270,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 546,
|
||||
"totalWeight": 3349,
|
||||
},
|
||||
Frame {
|
||||
"col": 47,
|
||||
"file": "extensions::binding",
|
||||
"key": "(anonymous):extensions::binding:322:47",
|
||||
"line": 322,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 159,
|
||||
"totalWeight": 586,
|
||||
},
|
||||
Frame {
|
||||
"col": 44,
|
||||
"file": "extensions::binding",
|
||||
"key": "(anonymous):extensions::binding:396:44",
|
||||
"line": 396,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 142,
|
||||
"totalWeight": 802,
|
||||
},
|
||||
Frame {
|
||||
"col": 16,
|
||||
"file": "extensions::event_bindings",
|
||||
"key": "Event:extensions::event_bindings:512:16",
|
||||
"line": 512,
|
||||
"name": "Event",
|
||||
"selfWeight": 139,
|
||||
"totalWeight": 527,
|
||||
},
|
||||
Frame {
|
||||
"col": 51,
|
||||
"file": "extensions::utils",
|
||||
"key": "privates.constructPrivate:extensions::utils:101:51",
|
||||
"line": 101,
|
||||
"name": "privates.constructPrivate",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 388,
|
||||
},
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "extensions::event_bindings",
|
||||
"key": "EventImpl:extensions::event_bindings:212:20",
|
||||
"line": 212,
|
||||
"name": "EventImpl",
|
||||
"selfWeight": 251,
|
||||
"totalWeight": 251,
|
||||
},
|
||||
Frame {
|
||||
"col": 26,
|
||||
"file": "extensions::binding",
|
||||
"key": "addProperties:extensions::binding:424:26",
|
||||
"line": 424,
|
||||
"name": "addProperties",
|
||||
"selfWeight": 149,
|
||||
"totalWeight": 710,
|
||||
},
|
||||
Frame {
|
||||
"col": 16,
|
||||
"file": "extensions::utils",
|
||||
"key": "forEach:extensions::utils:26:16",
|
||||
"line": 26,
|
||||
"name": "forEach",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 561,
|
||||
},
|
||||
Frame {
|
||||
"col": 21,
|
||||
"file": "extensions::binding",
|
||||
"key": "runHooks_:extensions::binding:179:21",
|
||||
"line": 179,
|
||||
"name": "runHooks_",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 273,
|
||||
},
|
||||
Frame {
|
||||
"col": 46,
|
||||
"file": "extensions::binding",
|
||||
"key": "(anonymous):extensions::binding:180:46",
|
||||
"line": 180,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 141,
|
||||
"totalWeight": 273,
|
||||
},
|
||||
Frame {
|
||||
"col": 35,
|
||||
"file": "extensions::runtime",
|
||||
"key": "(anonymous):extensions::runtime:16:35",
|
||||
"line": 16,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 132,
|
||||
"totalWeight": 132,
|
||||
},
|
||||
Frame {
|
||||
"col": 260,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "l:chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:37:260",
|
||||
"line": 37,
|
||||
"name": "l",
|
||||
"selfWeight": 127,
|
||||
"totalWeight": 127,
|
||||
},
|
||||
Frame {
|
||||
"col": 43,
|
||||
"file": "extensions::utils",
|
||||
"key": "publicClassPrototype.(anonymous function):extensions::utils:135:43",
|
||||
"line": 135,
|
||||
"name": "publicClassPrototype.(anonymous function)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 276,
|
||||
},
|
||||
Frame {
|
||||
"col": 44,
|
||||
"file": "extensions::event_bindings",
|
||||
"key": "EventImpl.addListener:extensions::event_bindings:272:44",
|
||||
"line": 272,
|
||||
"name": "EventImpl.addListener",
|
||||
"selfWeight": 135,
|
||||
"totalWeight": 135,
|
||||
},
|
||||
Frame {
|
||||
"col": 161,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "bb:chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:57:161",
|
||||
"line": 57,
|
||||
"name": "bb",
|
||||
"selfWeight": 146,
|
||||
"totalWeight": 146,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "(anonymous):chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:64:9",
|
||||
"line": 64,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 141,
|
||||
"totalWeight": 1071,
|
||||
},
|
||||
Frame {
|
||||
"col": 46,
|
||||
"file": "extensions::SafeBuiltins",
|
||||
"key": "(anonymous):extensions::SafeBuiltins:65:46",
|
||||
"line": 65,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 116,
|
||||
"totalWeight": 27605,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js",
|
||||
"key": "(anonymous):chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js:0:0",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 542,
|
||||
"totalWeight": 6218,
|
||||
},
|
||||
Frame {
|
||||
"col": 25,
|
||||
"file": "chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js",
|
||||
"key": "insertTextScript:chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js:30:25",
|
||||
"line": 30,
|
||||
"name": "insertTextScript",
|
||||
"selfWeight": 392,
|
||||
"totalWeight": 977,
|
||||
},
|
||||
Frame {
|
||||
"col": 25,
|
||||
"file": "chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js",
|
||||
"key": "insertHeaderNode:chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js:57:25",
|
||||
"line": 57,
|
||||
"name": "insertHeaderNode",
|
||||
"selfWeight": 292,
|
||||
"totalWeight": 585,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "appendChild:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "appendChild",
|
||||
"selfWeight": 145,
|
||||
"totalWeight": 293,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": undefined,
|
||||
"key": "(anonymous):undefined:0:0",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 148,
|
||||
},
|
||||
Frame {
|
||||
"col": 13,
|
||||
"file": undefined,
|
||||
"key": "(anonymous):undefined:6:13",
|
||||
"line": 6,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 148,
|
||||
"totalWeight": 148,
|
||||
},
|
||||
Frame {
|
||||
"col": 25,
|
||||
"file": "chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js",
|
||||
"key": "listenForMessage:chrome-extension://denbgaamihkadbghdceggmchnflmhpmk/contentScript.js:24:25",
|
||||
"line": 24,
|
||||
"name": "listenForMessage",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4699,
|
||||
},
|
||||
Frame {
|
||||
"col": 9,
|
||||
"file": "extensions::uncaught_exception_handler",
|
||||
"key": "(anonymous):extensions::uncaught_exception_handler:0:9",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 121,
|
||||
"totalWeight": 121,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "(anonymous):undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 135,
|
||||
"totalWeight": 135,
|
||||
},
|
||||
Frame {
|
||||
"col": 8,
|
||||
"file": "http://127.0.0.1:8081/worker.html",
|
||||
"key": "(anonymous):http://127.0.0.1:8081/worker.html:0:8",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 939,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "Worker:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "Worker",
|
||||
"selfWeight": 416,
|
||||
"totalWeight": 939,
|
||||
},
|
||||
Frame {
|
||||
"col": 11,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "cb:chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:49:11",
|
||||
"line": 49,
|
||||
"name": "cb",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 359,
|
||||
},
|
||||
Frame {
|
||||
"col": 314,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "$a:chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:46:314",
|
||||
"line": 46,
|
||||
"name": "$a",
|
||||
"selfWeight": 278,
|
||||
"totalWeight": 359,
|
||||
},
|
||||
Frame {
|
||||
"col": 51,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "(anonymous):chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:50:51",
|
||||
"line": 50,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 683,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "setTimeout:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "setTimeout",
|
||||
"selfWeight": 63,
|
||||
"totalWeight": 704,
|
||||
},
|
||||
Frame {
|
||||
"col": 144,
|
||||
"file": "chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js",
|
||||
"key": "(anonymous):chrome-extension://aomjjhallfgjeglblehebfpbcfeobpgk/injected.min.js:50:144",
|
||||
"line": 50,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 117,
|
||||
"totalWeight": 678,
|
||||
},
|
||||
Frame {
|
||||
"col": 29,
|
||||
"file": "http://127.0.0.1:8081/worker.html",
|
||||
"key": "worker.onmessage:http://127.0.0.1:8081/worker.html:19:29",
|
||||
"line": 19,
|
||||
"name": "worker.onmessage",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 21103,
|
||||
},
|
||||
Frame {
|
||||
"col": 16,
|
||||
"file": "http://127.0.0.1:8081/worker.html",
|
||||
"key": "apple:http://127.0.0.1:8081/worker.html:9:16",
|
||||
"line": 9,
|
||||
"name": "apple",
|
||||
"selfWeight": 660,
|
||||
"totalWeight": 20852,
|
||||
},
|
||||
Frame {
|
||||
"col": 17,
|
||||
"file": "http://127.0.0.1:8081/worker.html",
|
||||
"key": "banana:http://127.0.0.1:8081/worker.html:1:17",
|
||||
"line": 1,
|
||||
"name": "banana",
|
||||
"selfWeight": 18755,
|
||||
"totalWeight": 20192,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "postMessage:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "postMessage",
|
||||
"selfWeight": 251,
|
||||
"totalWeight": 251,
|
||||
},
|
||||
],
|
||||
"name": "worker.json - CrRendererMain",
|
||||
"stacks": Array [
|
||||
" 15.06ms",
|
||||
"(anonymous);(anonymous);saveBuiltin;makeCallable;(anonymous) 102.00µs",
|
||||
"(anonymous);(anonymous);saveBuiltin 92.00µs",
|
||||
"(anonymous);(anonymous);saveBuiltin;(program) 2.62ms",
|
||||
" 312.00µs",
|
||||
"(program) 295.00µs",
|
||||
" 105.00µs",
|
||||
"(program) 306.00µs",
|
||||
" 111.00µs",
|
||||
"(program) 109.00µs",
|
||||
" 197.00µs",
|
||||
"(program) 110.00µs",
|
||||
"(program);(garbage collector) 102.00µs",
|
||||
"(program) 1.25ms",
|
||||
"(anonymous);(anonymous);saveBuiltin 141.00µs",
|
||||
"(anonymous);(anonymous);saveBuiltin;makeCallable 122.00µs",
|
||||
"(anonymous);(anonymous);saveBuiltin;makeCallable;(program) 6.65ms",
|
||||
"(anonymous) 598.00µs",
|
||||
"(anonymous);(garbage collector) 778.00µs",
|
||||
"(anonymous) 660.00µs",
|
||||
"(anonymous);La 407.00µs",
|
||||
"(anonymous);La;get webstore 139.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous) 1.15ms",
|
||||
"(anonymous);La;get webstore;(anonymous);privates 132.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous) 791.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates 135.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous) 669.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 375.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates 134.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 256.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates 135.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 847.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates 133.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 580.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous) 153.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);expose;target.(anonymous function);Apply 146.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous) 744.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous) 151.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates;(anonymous);expose 147.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates 141.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous) 146.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);privates 139.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous) 142.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;privates 120.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;shouldCheckUnprivileged;target.(anonymous function);Apply 146.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply 259.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);JSONSchemaValidator.addTypes 149.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply 153.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply 251.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous);target.(anonymous function) 292.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous) 295.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply 152.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous) 159.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);privates 135.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);privates 133.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);Event 139.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);Event;privates.constructPrivate;target.(anonymous function);Apply 137.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);Event;privates.constructPrivate;target.(anonymous function);Apply;EventImpl 125.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous) 142.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;addProperties 149.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;addProperties;forEach;target.(anonymous function);Apply 126.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate 149.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;runHooks_;target.(anonymous function);Apply;(anonymous) 141.00µs",
|
||||
"(anonymous);La;get webstore;(anonymous);generate;runHooks_;target.(anonymous function);Apply;(anonymous);(anonymous) 132.00µs",
|
||||
"(anonymous) 160.00µs",
|
||||
"(anonymous);l 127.00µs",
|
||||
"(anonymous) 132.00µs",
|
||||
"(anonymous);publicClassPrototype.(anonymous function);target.(anonymous function);Apply 141.00µs",
|
||||
"(anonymous);publicClassPrototype.(anonymous function);target.(anonymous function);Apply;EventImpl.addListener 135.00µs",
|
||||
"(anonymous);bb 146.00µs",
|
||||
"(anonymous);(anonymous) 141.00µs",
|
||||
"(anonymous);(anonymous);(program) 930.00µs",
|
||||
"(anonymous);(anonymous);saveBuiltin;makeCallable;(anonymous) 132.00µs",
|
||||
"(anonymous);(anonymous);(anonymous) 116.00µs",
|
||||
"(anonymous);(anonymous);(anonymous);(program) 27.49ms",
|
||||
"(anonymous) 542.00µs",
|
||||
"(anonymous);insertTextScript 392.00µs",
|
||||
"(anonymous);insertTextScript;insertHeaderNode 292.00µs",
|
||||
"(anonymous);insertTextScript;insertHeaderNode;appendChild;(anonymous);(anonymous) 148.00µs",
|
||||
"(anonymous);insertTextScript;insertHeaderNode;appendChild 145.00µs",
|
||||
"(anonymous);listenForMessage;get webstore 148.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 121.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 130.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous);privates;(anonymous) 254.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);privates;(anonymous);privates;(anonymous);(anonymous) 135.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);privates 122.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);privates;(anonymous);target.(anonymous function);Apply 130.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous) 141.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function) 154.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous) 123.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous);target.(anonymous function) 137.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply 257.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(garbage collector) 1.58ms",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous) 128.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply;(anonymous);target.(anonymous function);Apply 289.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);privates 292.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;target.(anonymous function);Apply;(anonymous);Event;privates.constructPrivate;target.(anonymous function);Apply;EventImpl 126.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;addProperties;forEach;target.(anonymous function) 144.00µs",
|
||||
"(anonymous);listenForMessage;get webstore;(anonymous);generate;addProperties;forEach;target.(anonymous function);(program) 291.00µs",
|
||||
"(anonymous);Worker 416.00µs",
|
||||
"(anonymous);Worker;(program) 523.00µs",
|
||||
"cb;$a 278.00µs",
|
||||
"cb;$a;(program) 81.00µs",
|
||||
"(anonymous);setTimeout 42.00µs",
|
||||
"(anonymous);setTimeout;(program) 641.00µs",
|
||||
"(anonymous);setTimeout 21.00µs",
|
||||
"(anonymous) 117.00µs",
|
||||
"(anonymous);(program) 540.00µs",
|
||||
" 511.00µs",
|
||||
"(program) 125.00µs",
|
||||
" 136.00µs",
|
||||
"(program) 1.06ms",
|
||||
" 133.00µs",
|
||||
"(program) 1.46ms",
|
||||
" 261.00µs",
|
||||
"(program) 147.00µs",
|
||||
" 4.74ms",
|
||||
"(program) 145.00µs",
|
||||
" 525.00µs",
|
||||
"(program) 221.00µs",
|
||||
" 325.00µs",
|
||||
"(program) 399.00µs",
|
||||
" 146.00µs",
|
||||
"(program) 391.00µs",
|
||||
" 4.01ms",
|
||||
"(program) 131.00µs",
|
||||
" 1.10ms",
|
||||
"(program) 146.00µs",
|
||||
" 2.91ms",
|
||||
"(program) 280.00µs",
|
||||
"worker.onmessage;apple;banana 420.00µs",
|
||||
"worker.onmessage;apple 128.00µs",
|
||||
"worker.onmessage;apple;banana 1.27ms",
|
||||
"worker.onmessage;apple 146.00µs",
|
||||
"worker.onmessage;apple;banana 1.06ms",
|
||||
"worker.onmessage;apple 130.00µs",
|
||||
"worker.onmessage;apple;banana 129.00µs",
|
||||
"worker.onmessage;postMessage 143.00µs",
|
||||
" 1.80ms",
|
||||
"worker.onmessage;apple;banana 1.53ms",
|
||||
"worker.onmessage;postMessage 108.00µs",
|
||||
" 1.63ms",
|
||||
"(program) 141.00µs",
|
||||
"worker.onmessage;apple;banana 1.86ms",
|
||||
" 1.75ms",
|
||||
"worker.onmessage;apple;banana 1.67ms",
|
||||
" 1.84ms",
|
||||
"worker.onmessage;apple;banana 1.62ms",
|
||||
"worker.onmessage;apple;banana;(program) 146.00µs",
|
||||
" 1.67ms",
|
||||
"worker.onmessage;apple;banana 1.45ms",
|
||||
"worker.onmessage;apple;banana;(garbage collector) 923.00µs",
|
||||
"worker.onmessage;apple;banana 136.00µs",
|
||||
"worker.onmessage;apple;banana;(program) 132.00µs",
|
||||
" 1.81ms",
|
||||
"(program) 136.00µs",
|
||||
"worker.onmessage;apple;banana 1.69ms",
|
||||
" 1.75ms",
|
||||
"(program) 131.00µs",
|
||||
"worker.onmessage;apple;banana 282.00µs",
|
||||
"worker.onmessage;apple 128.00µs",
|
||||
"worker.onmessage;apple;banana 1.10ms",
|
||||
"worker.onmessage;apple;banana;(program) 136.00µs",
|
||||
" 1.57ms",
|
||||
"worker.onmessage;apple;banana 665.00µs",
|
||||
"worker.onmessage;apple 128.00µs",
|
||||
"worker.onmessage;apple;banana 779.00µs",
|
||||
" 1.56ms",
|
||||
"(program) 131.00µs",
|
||||
"worker.onmessage;apple;banana 1.56ms",
|
||||
" 1.57ms",
|
||||
"(program) 149.00µs",
|
||||
"worker.onmessage;apple;banana 1.54ms",
|
||||
"worker.onmessage;apple;banana;(program) 100.00µs",
|
||||
" 52.45ms",
|
||||
"(program) 125.00µs",
|
||||
" 88.71ms",
|
||||
"(program) 1.06ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 70 2`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": 20,
|
||||
"file": "http://127.0.0.1:8081/worker.js",
|
||||
"key": "onmessage:http://127.0.0.1:8081/worker.js:14:20",
|
||||
"line": 14,
|
||||
"name": "onmessage",
|
||||
"selfWeight": 402,
|
||||
"totalWeight": 187278,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "http://127.0.0.1:8081/worker.js",
|
||||
"key": "alpha:http://127.0.0.1:8081/worker.js:8:14",
|
||||
"line": 8,
|
||||
"name": "alpha",
|
||||
"selfWeight": 7945,
|
||||
"totalWeight": 177837,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "http://127.0.0.1:8081/worker.js",
|
||||
"key": "gamma:http://127.0.0.1:8081/worker.js:0:14",
|
||||
"line": 0,
|
||||
"name": "gamma",
|
||||
"selfWeight": 13631,
|
||||
"totalWeight": 21888,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "(program):undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "(program)",
|
||||
"selfWeight": 164753,
|
||||
"totalWeight": 164753,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "postMessage:undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "postMessage",
|
||||
"selfWeight": 547,
|
||||
"totalWeight": 5452,
|
||||
},
|
||||
],
|
||||
"name": "worker.json - DedicatedWorker thread",
|
||||
"stacks": Array [
|
||||
" 4.33ms",
|
||||
"onmessage;alpha;gamma 604.00µs",
|
||||
"onmessage;alpha 1.38ms",
|
||||
"onmessage;alpha;gamma 3.31ms",
|
||||
"onmessage 270.00µs",
|
||||
"onmessage;(program) 3.59ms",
|
||||
"onmessage;alpha;gamma 127.00µs",
|
||||
"onmessage;alpha 128.00µs",
|
||||
"onmessage;alpha;gamma 1.48ms",
|
||||
"onmessage;alpha;gamma;(program) 1.68ms",
|
||||
"onmessage;alpha;gamma 1.65ms",
|
||||
"onmessage;alpha;gamma;(program) 2.00ms",
|
||||
"onmessage;alpha;gamma 1.62ms",
|
||||
"onmessage;postMessage 146.00µs",
|
||||
"onmessage;postMessage;(program) 1.65ms",
|
||||
"onmessage;alpha;gamma 1.70ms",
|
||||
"onmessage;postMessage 256.00µs",
|
||||
"onmessage;postMessage;(program) 1.63ms",
|
||||
"onmessage;alpha;gamma 670.00µs",
|
||||
"onmessage;alpha 134.00µs",
|
||||
"onmessage;alpha;gamma 899.00µs",
|
||||
"onmessage;alpha;gamma;(program) 2.72ms",
|
||||
"onmessage 132.00µs",
|
||||
"onmessage;alpha;gamma 1.57ms",
|
||||
"onmessage;alpha;gamma;(program) 1.85ms",
|
||||
"onmessage;alpha 1.75ms",
|
||||
"onmessage;alpha;(program) 1.76ms",
|
||||
"onmessage;alpha 1.44ms",
|
||||
"onmessage;postMessage 145.00µs",
|
||||
"onmessage;postMessage;(program) 1.63ms",
|
||||
"onmessage;alpha 1.57ms",
|
||||
"onmessage;alpha;(program) 1.60ms",
|
||||
"onmessage;alpha 1.55ms",
|
||||
"onmessage;alpha;(program) 144.64ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 70: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 70: profileGroup.name 1`] = `"worker.json"`;
|
||||
|
||||
exports[`importFromChromeTimeline: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromChromeTimeline: profileGroup.name 1`] = `"simple-timeline.json"`;
|
||||
|
||||
exports[`importFromV8Profiler Node 10 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "",
|
||||
"key": "(anonymous)::0:0",
|
||||
"line": 0,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 11575,
|
||||
"totalWeight": 44777,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "",
|
||||
"key": "a::0:0",
|
||||
"line": 0,
|
||||
"name": "a",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 33202,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "",
|
||||
"key": "b::5:0",
|
||||
"line": 5,
|
||||
"name": "b",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 16788,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "",
|
||||
"key": "d::13:0",
|
||||
"line": 13,
|
||||
"name": "d",
|
||||
"selfWeight": 33202,
|
||||
"totalWeight": 33202,
|
||||
},
|
||||
Frame {
|
||||
"col": 0,
|
||||
"file": "",
|
||||
"key": "c::9:0",
|
||||
"line": 9,
|
||||
"name": "c",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 16414,
|
||||
},
|
||||
],
|
||||
"name": "example.cpuprofile",
|
||||
"stacks": Array [
|
||||
" 599.29ms",
|
||||
"(anonymous) 11.57ms",
|
||||
"(anonymous);a;b;d 16.79ms",
|
||||
"(anonymous);a;c;d 16.41ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromV8Profiler Node 10: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromV8Profiler Node 10: profileGroup.name 1`] = `"example.cpuprofile"`;
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importTraceEvents multiprocess 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "alpha",
|
||||
"line": undefined,
|
||||
"name": "alpha",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p0 (pid 0), p0t0 (tid 0)",
|
||||
"stacks": Array [
|
||||
"alpha 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 2`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "beta",
|
||||
"line": undefined,
|
||||
"name": "beta",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p0 (pid 0), p0t1 (tid 1)",
|
||||
"stacks": Array [
|
||||
"beta 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 3`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "gamma",
|
||||
"line": undefined,
|
||||
"name": "gamma",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p1 (pid 1), p1t0 (tid 0)",
|
||||
"stacks": Array [
|
||||
"gamma 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 4`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "delta",
|
||||
"line": undefined,
|
||||
"name": "delta",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p1 (pid 1), p1t1 (tid 1)",
|
||||
"stacks": Array [
|
||||
"delta 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 5`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "epsilon",
|
||||
"line": undefined,
|
||||
"name": "epsilon",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p2t0 (pid 2, tid 0)",
|
||||
"stacks": Array [
|
||||
"epsilon 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 6`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "phi",
|
||||
"line": undefined,
|
||||
"name": "phi",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p2t1 (pid 2, tid 1)",
|
||||
"stacks": Array [
|
||||
"phi 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 7`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "zeta",
|
||||
"line": undefined,
|
||||
"name": "zeta",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p3 (pid 3, tid 0)",
|
||||
"stacks": Array [
|
||||
"zeta 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 8`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "eta",
|
||||
"line": undefined,
|
||||
"name": "eta",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "p3 (pid 3, tid 1)",
|
||||
"stacks": Array [
|
||||
"eta 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multiprocess: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents multiprocess: profileGroup.name 1`] = `"multiprocess.json"`;
|
||||
|
||||
exports[`importTraceEvents simple 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 simple object 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": 8,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "(unnamed)",
|
||||
"line": undefined,
|
||||
"name": "(unnamed)",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"alpha 1.00µs",
|
||||
"alpha;beta 6.00µs",
|
||||
"alpha;beta;(unnamed) 4.00µs",
|
||||
"alpha;beta 2.00µs",
|
||||
"alpha 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents simple object: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents simple object: profileGroup.name 1`] = `"simple-object.json"`;
|
||||
|
||||
exports[`importTraceEvents simple: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents simple: profileGroup.name 1`] = `"simple.json"`;
|
||||
@@ -11,3 +11,11 @@ test('importFromChromeTimeline', async () => {
|
||||
test('importFromChromeTimeline Chrome 69', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Chrome/69/simple.json')
|
||||
})
|
||||
|
||||
test('importFromV8Profiler Node 10', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/node/10.11.0/example.cpuprofile')
|
||||
})
|
||||
|
||||
test('importFromChromeTimeline Workers Chrome 70', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Chrome/70/worker.json')
|
||||
})
|
||||
|
||||
+68
-15
@@ -1,6 +1,7 @@
|
||||
import {Profile, FrameInfo, CallTreeProfileBuilder} from '../lib/profile'
|
||||
import {getOrInsert, lastOf, sortBy} from '../lib/utils'
|
||||
import {Profile, FrameInfo, CallTreeProfileBuilder, ProfileGroup} from '../lib/profile'
|
||||
import {getOrInsert, lastOf, sortBy, itForEach} from '../lib/utils'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
import {chromeTreeToNodes, OldCPUProfile} from './v8cpuFormatter'
|
||||
|
||||
// See: https://github.com/v8/v8/blob/master/src/inspector/js_protocol.json
|
||||
|
||||
@@ -15,6 +16,7 @@ interface TimelineEvent {
|
||||
tdur: number
|
||||
tts: number
|
||||
args: {[key: string]: any}
|
||||
id?: string
|
||||
}
|
||||
|
||||
interface PositionTickInfo {
|
||||
@@ -30,7 +32,7 @@ interface CPUProfileCallFrame {
|
||||
url: string
|
||||
}
|
||||
|
||||
interface CPUProfileNode {
|
||||
export interface CPUProfileNode {
|
||||
callFrame: CPUProfileCallFrame
|
||||
hitCount: number
|
||||
id: number
|
||||
@@ -39,7 +41,7 @@ interface CPUProfileNode {
|
||||
parent?: CPUProfileNode
|
||||
}
|
||||
|
||||
interface CPUProfile {
|
||||
export interface CPUProfile {
|
||||
startTime: number
|
||||
endTime: number
|
||||
nodes: CPUProfileNode[]
|
||||
@@ -61,33 +63,54 @@ export function isChromeTimeline(rawProfile: any): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
export function importFromChromeTimeline(events: TimelineEvent[]): Profile {
|
||||
export function importFromChromeTimeline(events: TimelineEvent[], fileName: string): ProfileGroup {
|
||||
// It seems like sometimes Chrome timeline files contain multiple CpuProfiles?
|
||||
// For now, choose the first one in the list.
|
||||
|
||||
let cpuProfile: CPUProfile | null = null
|
||||
const cpuProfileByID = new Map<string, CPUProfile>()
|
||||
|
||||
// Maps profile IDs (like "0x3") to pid/tid pairs formatted as `${pid}:${tid}`
|
||||
const pidTidById = new Map<string, string>()
|
||||
|
||||
// Maps pid/tid pairs to thread names
|
||||
const threadNameByPidTid = new Map<string, string>()
|
||||
|
||||
// The events aren't necessarily recorded in chronological order. Sort them so
|
||||
// that they are.
|
||||
sortBy(events, e => e.ts)
|
||||
|
||||
const DEFAULT_ID = '(default id)'
|
||||
|
||||
for (let event of events) {
|
||||
if (event.name == 'CpuProfile') {
|
||||
cpuProfile = event.args.data.cpuProfile as CPUProfile
|
||||
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}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (event.name == 'Profile') {
|
||||
cpuProfile = {
|
||||
if (event.name === 'Profile') {
|
||||
cpuProfileByID.set(event.id || DEFAULT_ID, {
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
nodes: [],
|
||||
samples: [],
|
||||
timeDeltas: [],
|
||||
...event.args.data,
|
||||
})
|
||||
|
||||
if (event.id) {
|
||||
pidTidById.set(event.id, `${event.pid}:${event.tid}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (event.name == 'ProfileChunk') {
|
||||
if (event.name === 'thread_name') {
|
||||
threadNameByPidTid.set(`${event.pid}:${event.tid}`, event.args.name)
|
||||
}
|
||||
|
||||
if (event.name === 'ProfileChunk') {
|
||||
const cpuProfile = cpuProfileByID.get(event.id || DEFAULT_ID)
|
||||
if (cpuProfile) {
|
||||
const chunk = event.args.data
|
||||
if (chunk.cpuProfile) {
|
||||
@@ -108,13 +131,38 @@ export function importFromChromeTimeline(events: TimelineEvent[]): Profile {
|
||||
cpuProfile.endTime = chunk.endTime
|
||||
}
|
||||
} else {
|
||||
console.log('Ignoring ProfileChunk when no Profile is active')
|
||||
console.warn(
|
||||
`Ignoring ProfileChunk for undeclared Profile with id ${event.id || DEFAULT_ID}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cpuProfile) {
|
||||
return importFromChromeCPUProfile(cpuProfile as CPUProfile)
|
||||
if (cpuProfileByID.size > 0) {
|
||||
const profiles: Profile[] = []
|
||||
let indexToView = 0
|
||||
|
||||
itForEach(cpuProfileByID.keys(), profileId => {
|
||||
let threadName: string | null = null
|
||||
let pidTid = pidTidById.get(profileId)
|
||||
if (pidTid) {
|
||||
threadName = threadNameByPidTid.get(pidTid) || null
|
||||
if (threadName) {
|
||||
}
|
||||
}
|
||||
const profile = importFromChromeCPUProfile(cpuProfileByID.get(profileId)!)
|
||||
if (threadName && cpuProfileByID.size > 1) {
|
||||
profile.setName(`${fileName} - ${threadName}`)
|
||||
if (threadName === 'CrRendererMain') {
|
||||
indexToView = profiles.length
|
||||
}
|
||||
} else {
|
||||
profile.setName(`${fileName}`)
|
||||
}
|
||||
profiles.push(profile)
|
||||
})
|
||||
|
||||
return {name: fileName, indexToView, profiles}
|
||||
} else {
|
||||
throw new Error('Could not find CPU profile in Timeline')
|
||||
}
|
||||
@@ -198,7 +246,8 @@ export function importFromChromeCPUProfile(chromeProfile: CPUProfile): Profile {
|
||||
} else {
|
||||
let timeDelta = chromeProfile.timeDeltas[i + 1]
|
||||
if (timeDelta < 0) {
|
||||
console.warn('Substituting zero for unexpected time delta:', timeDelta, 'at index', i)
|
||||
// This is super noisy, but can be helpful when debugging strange data
|
||||
// console.warn('Substituting zero for unexpected time delta:', timeDelta, 'at index', i)
|
||||
timeDelta = 0
|
||||
}
|
||||
|
||||
@@ -264,3 +313,7 @@ export function importFromChromeCPUProfile(chromeProfile: CPUProfile): Profile {
|
||||
profile.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
return profile.build()
|
||||
}
|
||||
|
||||
export function importFromOldV8CPUProfile(content: OldCPUProfile): Profile {
|
||||
return importFromChromeCPUProfile(chromeTreeToNodes(content))
|
||||
}
|
||||
|
||||
+17
-8
@@ -1,7 +1,12 @@
|
||||
import {Profile, ProfileGroup} from '../lib/profile'
|
||||
import {FileSystemDirectoryEntry} from './file-system-entry'
|
||||
|
||||
import {importFromChromeCPUProfile, importFromChromeTimeline, isChromeTimeline} from './chrome'
|
||||
import {
|
||||
importFromChromeCPUProfile,
|
||||
importFromChromeTimeline,
|
||||
isChromeTimeline,
|
||||
importFromOldV8CPUProfile,
|
||||
} from './chrome'
|
||||
import {importFromStackprof} from './stackprof'
|
||||
import {importFromInstrumentsDeepCopy, importFromInstrumentsTrace} from './instruments'
|
||||
import {importFromBGFlameGraph} from './bg-flamegraph'
|
||||
@@ -14,6 +19,7 @@ import {ProfileDataSource, TextProfileDataSource, MaybeCompressedDataReader} fro
|
||||
import {importAsPprofProfile} from './pprof'
|
||||
import {decodeBase64} from '../lib/utils'
|
||||
import {importFromChromeHeapProfile} from './v8heapalloc'
|
||||
import {isTraceEventFormatted, importTraceEvents} from './trace-event'
|
||||
|
||||
export async function importProfileGroupFromText(
|
||||
fileName: string,
|
||||
@@ -84,12 +90,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
if (fileName.endsWith('.speedscope.json')) {
|
||||
console.log('Importing as speedscope json file')
|
||||
return importSpeedscopeProfiles(JSON.parse(contents))
|
||||
} else if (fileName.endsWith('.cpuprofile')) {
|
||||
console.log('Importing as Chrome CPU Profile')
|
||||
return toGroup(importFromChromeCPUProfile(JSON.parse(contents)))
|
||||
} else if (fileName.endsWith('.chrome.json') || /Profile-\d{8}T\d{6}/.exec(fileName)) {
|
||||
console.log('Importing as Chrome Timeline')
|
||||
return toGroup(importFromChromeTimeline(JSON.parse(contents)))
|
||||
return importFromChromeTimeline(JSON.parse(contents), fileName)
|
||||
} else if (fileName.endsWith('.stackprof.json')) {
|
||||
console.log('Importing as stackprof profile')
|
||||
return toGroup(importFromStackprof(JSON.parse(contents)))
|
||||
@@ -123,11 +126,17 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
console.log('Importing as Firefox profile')
|
||||
return toGroup(importFromFirefox(parsed))
|
||||
} else if (isChromeTimeline(parsed)) {
|
||||
console.log('Importing as Chrome CPU Profile')
|
||||
return toGroup(importFromChromeTimeline(parsed))
|
||||
} else if ('nodes' in parsed && 'samples' in parsed && 'timeDeltas' in parsed) {
|
||||
console.log('Importing as Chrome Timeline')
|
||||
return importFromChromeTimeline(parsed, fileName)
|
||||
} else if ('nodes' in parsed && 'samples' in parsed && 'timeDeltas' in parsed) {
|
||||
console.log('Importing as Chrome CPU Profile')
|
||||
return toGroup(importFromChromeCPUProfile(parsed))
|
||||
} else if (isTraceEventFormatted(parsed)) {
|
||||
console.log('Importing as Trace Event Format profile')
|
||||
return importTraceEvents(parsed)
|
||||
} 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) {
|
||||
console.log('Importing as stackprof profile')
|
||||
return toGroup(importFromStackprof(parsed))
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import {checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
test('importTraceEvents simple', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents simple object', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-object.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents multiprocess', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/multiprocess.json')
|
||||
})
|
||||
@@ -0,0 +1,291 @@
|
||||
import {sortBy, zeroPad} from '../lib/utils'
|
||||
import {ProfileGroup, CallTreeProfileBuilder, FrameInfo} from '../lib/profile'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
|
||||
// This file concerns import from the "Trace Event Format", authored by Google
|
||||
// and used for Google's own chrome://trace.
|
||||
//
|
||||
// The file format is extremely general, and we only support the parts of it
|
||||
// that logically map onto speedscope's visualization capabilities.
|
||||
// Specifically, we only support the "B", "E", and "X" event types. Everything
|
||||
// else is ignored. We do, however, support import of profiles that are
|
||||
// multi-process/multi-threaded. Each process is split into a separate profile.
|
||||
//
|
||||
// Note that Chrome Developer Tools uses this format as well, but all the
|
||||
// relevant data used in those profiles is stored in events with the name
|
||||
// "CpuProfile", "Profile", or "ProfileChunk". If we detect those, we prioritize
|
||||
// importing the profile as a Chrome Developer Tools profile. Otherwise,
|
||||
// we try to import it as a "Trace Event Format" file.
|
||||
//
|
||||
// Spec: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
|
||||
|
||||
interface TraceEvent {
|
||||
// The process ID for the process that output this event.
|
||||
pid: number
|
||||
|
||||
// The thread ID for the thread that output this event.
|
||||
tid: number
|
||||
|
||||
// The event type. This is a single character which changes depending on the type of event being output. The valid values are listed in the table below. We will discuss each phase type below.
|
||||
ph: string
|
||||
|
||||
// The tracing clock timestamp of the event. The timestamps are provided at microsecond granularity.
|
||||
ts: number
|
||||
|
||||
// The thread clock timestamp of the event. The timestamps are provided at microsecond granularity.
|
||||
tts?: number
|
||||
|
||||
// The name of the event, as displayed in Trace Viewer
|
||||
name?: string
|
||||
|
||||
// The event categories. This is a comma separated list of categories for the event. The categories can be used to hide events in the Trace Viewer UI.
|
||||
cat?: string
|
||||
|
||||
// Any arguments provided for the event. Some of the event types have required argument fields, otherwise, you can put any information you wish in here. The arguments are displayed in Trace Viewer when you view an event in the analysis section.
|
||||
args: any
|
||||
|
||||
// A fixed color name to associate with the event. If provided, cname must be one of the names listed in trace-viewer's base color scheme's reserved color names list
|
||||
cname?: string
|
||||
}
|
||||
|
||||
interface BTraceEvent extends TraceEvent {
|
||||
ph: 'B'
|
||||
}
|
||||
|
||||
interface ETraceEvent extends TraceEvent {
|
||||
ph: 'E'
|
||||
}
|
||||
|
||||
interface XTraceEvent extends TraceEvent {
|
||||
ph: 'X'
|
||||
dur?: number
|
||||
tdur?: number
|
||||
}
|
||||
|
||||
// The trace format supports a number of event types that we ignore.
|
||||
type ImportableTraceEvent = BTraceEvent | ETraceEvent | XTraceEvent
|
||||
type DurationEvent = BTraceEvent | ETraceEvent
|
||||
|
||||
function filterIgnoredEventTypes(events: TraceEvent[]): ImportableTraceEvent[] {
|
||||
const ret: ImportableTraceEvent[] = []
|
||||
for (let ev of events) {
|
||||
switch (ev.ph) {
|
||||
case 'B':
|
||||
case 'E':
|
||||
case 'X':
|
||||
ret.push(ev as ImportableTraceEvent)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function convertToDurationEvents(events: ImportableTraceEvent[]): DurationEvent[] {
|
||||
const ret: DurationEvent[] = []
|
||||
for (let ev of events) {
|
||||
switch (ev.ph) {
|
||||
case 'B':
|
||||
ret.push(ev)
|
||||
break
|
||||
|
||||
case 'E':
|
||||
ret.push(ev)
|
||||
break
|
||||
|
||||
case 'X':
|
||||
let dur: number | null = null
|
||||
if (ev.dur != null) dur = ev.dur
|
||||
else if (ev.tdur != null) dur = ev.tdur
|
||||
|
||||
if (dur == null) {
|
||||
console.warn('Found a complete event (X) with no duration. Skipping: ', ev)
|
||||
continue
|
||||
}
|
||||
|
||||
ret.push({...ev, ph: 'B'} as BTraceEvent)
|
||||
ret.push({...ev, ph: 'E', ts: ev.ts + dur} as ETraceEvent)
|
||||
break
|
||||
|
||||
default:
|
||||
const _exhaustiveCheck: never = ev
|
||||
return _exhaustiveCheck
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function getProcessNamesByPid(events: TraceEvent[]): Map<number, string> {
|
||||
const processNamesByPid = new Map<number, string>()
|
||||
for (let ev of events) {
|
||||
if (ev.ph === 'M' && ev.name === 'process_name' && ev.args && ev.args.name) {
|
||||
processNamesByPid.set(ev.pid, ev.args.name)
|
||||
}
|
||||
}
|
||||
return processNamesByPid
|
||||
}
|
||||
|
||||
function getThreadNamesByPidTid(events: TraceEvent[]): Map<string, string> {
|
||||
const threadNameByPidTid = new Map<string, string>()
|
||||
|
||||
for (let ev of events) {
|
||||
if (ev.ph === 'M' && ev.name === 'thread_name' && ev.args && ev.args.name) {
|
||||
const key = `${ev.pid}:${ev.tid}`
|
||||
threadNameByPidTid.set(key, ev.args.name)
|
||||
}
|
||||
}
|
||||
return threadNameByPidTid
|
||||
}
|
||||
|
||||
function keyForEvent(event: TraceEvent): string {
|
||||
let name = `${event.name || '(unnamed)'}`
|
||||
if (event.args) {
|
||||
name += ` ${JSON.stringify(event.args)}`
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
const profileByPidTid = new Map<string, CallTreeProfileBuilder>()
|
||||
|
||||
const importableEvents = filterIgnoredEventTypes(events)
|
||||
const durationEvents = convertToDurationEvents(importableEvents)
|
||||
|
||||
const processNamesByPid = getProcessNamesByPid(events)
|
||||
const threadNamesByPidTid = getThreadNamesByPidTid(events)
|
||||
|
||||
durationEvents.sort((a, b) => {
|
||||
if (a.ts < b.ts) return -1
|
||||
if (a.ts > b.ts) return 1
|
||||
|
||||
// We have to be careful with events that have the same timestamp
|
||||
if (a.pid === b.pid && a.tid === b.tid) {
|
||||
const aKey = keyForEvent(a)
|
||||
const bKey = keyForEvent(b)
|
||||
|
||||
if (aKey === bKey) {
|
||||
// If the two elements have the same key, we need to process the begin
|
||||
// event before the end event. This will be a zero-duration event.
|
||||
if (a.ph === 'B' && b.ph === 'E') return -1
|
||||
if (a.ph === 'E' && b.ph === 'B') return 1
|
||||
} else {
|
||||
// If the two elements have *different* keys, we want to process
|
||||
// the end of an event before the beginning of the event to prevent
|
||||
// out-of-order push/pops from the callstack.
|
||||
if (a.ph === 'B' && b.ph === 'E') return 1
|
||||
if (a.ph === 'E' && b.ph === 'B') return -1
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
})
|
||||
|
||||
if (durationEvents.length > 0) {
|
||||
const firstTs = durationEvents[0].ts
|
||||
for (let ev of durationEvents) {
|
||||
ev.ts -= firstTs
|
||||
}
|
||||
}
|
||||
|
||||
function getOrCreateProfile(pid: number, tid: number) {
|
||||
// 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()
|
||||
profile.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
profileByPidTid.set(pidTid, profile)
|
||||
|
||||
const processName = processNamesByPid.get(pid)
|
||||
const threadName = threadNamesByPidTid.get(`${pid}:${tid}`)
|
||||
|
||||
if (processName != null && threadName != null) {
|
||||
profile.setName(`${processName} (pid ${pid}), ${threadName} (tid ${tid})`)
|
||||
} else if (processName != null) {
|
||||
profile.setName(`${processName} (pid ${pid}, tid ${tid})`)
|
||||
} else if (threadName != null) {
|
||||
profile.setName(`${threadName} (pid ${pid}, tid ${tid})`)
|
||||
} else {
|
||||
profile.setName(`pid ${pid}, tid ${tid}`)
|
||||
}
|
||||
|
||||
return profile
|
||||
}
|
||||
|
||||
for (let ev of durationEvents) {
|
||||
const profile = getOrCreateProfile(ev.pid, ev.tid)
|
||||
const key = keyForEvent(ev)
|
||||
const frameInfo: FrameInfo = {
|
||||
key: key,
|
||||
name: key,
|
||||
}
|
||||
switch (ev.ph) {
|
||||
case 'B':
|
||||
profile.enterFrame(frameInfo, ev.ts)
|
||||
break
|
||||
|
||||
case 'E':
|
||||
profile.leaveFrame(frameInfo, ev.ts)
|
||||
break
|
||||
|
||||
default:
|
||||
const _exhaustiveCheck: never = ev
|
||||
return _exhaustiveCheck
|
||||
}
|
||||
}
|
||||
|
||||
// For now, we just sort processes by pid & tid.
|
||||
// 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())
|
||||
sortBy(profilePairs, p => p[0])
|
||||
|
||||
return {name: '', indexToView: 0, profiles: profilePairs.map(p => p[1])}
|
||||
}
|
||||
|
||||
function isTraceEventList(maybeEventList: any): maybeEventList is TraceEvent[] {
|
||||
if (!Array.isArray(maybeEventList)) return false
|
||||
if (maybeEventList.length === 0) return false
|
||||
|
||||
// Both ph and ts should be provided for every event. In theory, many other
|
||||
// fields are mandatory, but without these fields, we won't usefully be able
|
||||
// to import the data, so we'll rely upon these.
|
||||
for (let el of maybeEventList) {
|
||||
if (!('ph' in el) || !('ts' in el)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
function isTraceEventObject(
|
||||
maybeTraceEventObject: any,
|
||||
): maybeTraceEventObject is {traceEvents: TraceEvent[]} {
|
||||
if (!('traceEvents' in maybeTraceEventObject)) return false
|
||||
return isTraceEventList(maybeTraceEventObject['traceEvents'])
|
||||
}
|
||||
|
||||
export function isTraceEventFormatted(
|
||||
rawProfile: any,
|
||||
): rawProfile is {traceEvents: TraceEvent[]} | TraceEvent[] {
|
||||
// We're only going to suppor 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)
|
||||
}
|
||||
|
||||
export function importTraceEvents(
|
||||
rawProfile: {traceEvents: TraceEvent[]} | TraceEvent[],
|
||||
): ProfileGroup {
|
||||
if (isTraceEventObject(rawProfile)) {
|
||||
return eventListToProfileGroup(rawProfile.traceEvents)
|
||||
} else if (isTraceEventList(rawProfile)) {
|
||||
return eventListToProfileGroup(rawProfile)
|
||||
} else {
|
||||
const _exhaustiveCheck: never = rawProfile
|
||||
return _exhaustiveCheck
|
||||
}
|
||||
}
|
||||
+11
-6
@@ -53,13 +53,18 @@ export class MaybeCompressedDataReader implements ProfileDataSource {
|
||||
const buffer = await this.readAsArrayBuffer()
|
||||
let ret: string = ''
|
||||
|
||||
// JavaScript strings are UTF-16 encoded, but we're reading data
|
||||
// from disk that we're going to asusme is UTF-8 encoded.
|
||||
const array = new Uint8Array(buffer)
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
ret += String.fromCharCode(array[i])
|
||||
if (typeof TextDecoder !== 'undefined') {
|
||||
const decoder = new TextDecoder()
|
||||
return decoder.decode(buffer)
|
||||
} else {
|
||||
// JavaScript strings are UTF-16 encoded, but we're reading data
|
||||
// from disk that we're going to asusme is UTF-8 encoded.
|
||||
const array = new Uint8Array(buffer)
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
ret += String.fromCharCode(array[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
static fromFile(file: File): MaybeCompressedDataReader {
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import {CPUProfile, CPUProfileNode} from './chrome'
|
||||
|
||||
/**
|
||||
* This importer handles an old format used by the C++ API of V8. This format is still used by v8-profiler-node8.
|
||||
* There are two differences between the two formats:
|
||||
* - Nodes are a tree in the old format and a flat array in the new format
|
||||
* - Weights are timestamps in the old format and deltas in the new format.
|
||||
*
|
||||
* For more information, see https://github.com/hyj1991/v8-profiler-node8
|
||||
*/
|
||||
|
||||
interface OldCPUProfileNode {
|
||||
functionName: string
|
||||
lineNumber: number
|
||||
scriptId: string
|
||||
url: string
|
||||
hitCount: number
|
||||
bailoutReason: string
|
||||
id: number
|
||||
children: OldCPUProfileNode[]
|
||||
}
|
||||
|
||||
export interface OldCPUProfile {
|
||||
startTime: number
|
||||
endTime: number
|
||||
head: OldCPUProfileNode
|
||||
samples: number[]
|
||||
timestamps: number[]
|
||||
}
|
||||
|
||||
function treeToArray(root: OldCPUProfileNode): CPUProfileNode[] {
|
||||
const nodes: CPUProfileNode[] = []
|
||||
function visit(node: OldCPUProfileNode) {
|
||||
nodes.push({
|
||||
id: node.id,
|
||||
callFrame: {
|
||||
columnNumber: 0,
|
||||
functionName: node.functionName,
|
||||
lineNumber: node.lineNumber,
|
||||
scriptId: node.scriptId,
|
||||
url: node.url,
|
||||
},
|
||||
hitCount: node.hitCount,
|
||||
children: node.children.map(child => child.id),
|
||||
})
|
||||
node.children.forEach(visit)
|
||||
}
|
||||
visit(root)
|
||||
return nodes
|
||||
}
|
||||
|
||||
function timestampsToDeltas(timestamps: number[], startTime: number): number[] {
|
||||
return timestamps.map((timestamp, index) => {
|
||||
const lastTimestamp = index === 0 ? startTime * 1000000 : timestamps[index - 1]
|
||||
return timestamp - lastTimestamp
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the old tree-based format to the new flat-array based format
|
||||
*/
|
||||
export function chromeTreeToNodes(content: OldCPUProfile): CPUProfile {
|
||||
// Note that both startTime and endTime are now in microseconds
|
||||
return {
|
||||
samples: content.samples,
|
||||
startTime: content.startTime * 1000000,
|
||||
endTime: content.endTime * 1000000,
|
||||
nodes: treeToArray(content.head),
|
||||
timeDeltas: timestampsToDeltas(content.timestamps, content.startTime),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user