Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
650e505b55 | ||
|
|
8dad28e5e2 | ||
|
|
f62519ab69 | ||
|
|
984bf1296a | ||
|
|
26884c116c | ||
|
|
bb063e49e3 | ||
|
|
693545b77a | ||
|
|
b3b4b1492a | ||
|
|
9cdceede15 | ||
|
|
741fdeb427 | ||
|
|
e9133be353 | ||
|
|
fcc1fa5689 | ||
|
|
0414c2f617 | ||
|
|
f23f65b3af | ||
|
|
8da9088ec1 |
@@ -1,3 +1,28 @@
|
||||
## [1.16.0] - 2023-07-16
|
||||
|
||||
- Automate more of the release process [[#439](https://github.com/jlfwong/speedscope/pull/439)] (by @jlfwong)
|
||||
- Improve profile builder performance [[#437](https://github.com/jlfwong/speedscope/pull/437)] (by @Goose97)
|
||||
- Fix crash when importing big linux perf tool files [[#435](https://github.com/jlfwong/speedscope/pull/435)] (by @Goose97)
|
||||
- Improve splitLines: return iterator instead [[#434](https://github.com/jlfwong/speedscope/pull/434)] (by @Goose97)
|
||||
- Fix trimTextMid [[#431](https://github.com/jlfwong/speedscope/pull/431)] (by @jlfwong)
|
||||
- Added support for Papyrus profiles [[#428](https://github.com/jlfwong/speedscope/pull/428)] (by @xieve)
|
||||
|
||||
## [1.15.2] - 2023-06-21
|
||||
|
||||
### Fixed
|
||||
|
||||
- Use more accurate line information for pprof profiles [[#430](https://github.com/jlfwong/speedscope/pull/430)] (by @dalehamel)
|
||||
- Stackprof: weight on-cpu samples by period rather than timestamp delta [[#425](https://github.com/jlfwong/speedscope/pull/425)] (by @manuelfelipe)
|
||||
- Prevent crashes when stackprof profiles frames are missing names [[#419](https://github.com/jlfwong/speedscope/pull/419)] (by @jez)
|
||||
- fix pprof defaultSampleType [[#424](https://github.com/jlfwong/speedscope/pull/424)] (by @vasi-stripe)
|
||||
|
||||
## [1.15.1] - 2023-06-04
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix import from Chrome Devtools performance tab in Chrome >= 114 [[#422](https://github.com/jlfwong/speedscope/pull/422)]
|
||||
- Callgrind: Subposition compression and weight correction [[#423](https://github.com/jlfwong/speedscope/pull/423)]
|
||||
|
||||
## [1.15.0] - 2022-10-22
|
||||
|
||||
### Fixed
|
||||
|
||||
+12
-58
@@ -1,15 +1,5 @@
|
||||
This document describes processes needed by admins of this repository.
|
||||
|
||||
# Publishing
|
||||
|
||||
Publishing speedscope is a multi-step process:
|
||||
|
||||
1. Test the release
|
||||
2. Prepare the release
|
||||
3. Publish to npm
|
||||
4. Deploy the website
|
||||
5. Upload a release to GitHub
|
||||
|
||||
At time of writing, deployment assumes you're running macOS. It probably
|
||||
works if you're on a linux, and almost definitely does not work on Windows.
|
||||
|
||||
@@ -18,8 +8,9 @@ works if you're on a linux, and almost definitely does not work on Windows.
|
||||
Speedscope is tested in CI, so all the automated tests should be passing. We'll
|
||||
just be doing a few sanity checks to make sure the build & deployment machinery is working correctly.
|
||||
|
||||
Run `scripts/prepare-test-installation.sh`. This will do a mock publish &
|
||||
installation to ensure that the version we're about to publish is going to
|
||||
scripts/prepare-test-installation.sh
|
||||
|
||||
This will do a mock publish & installation to ensure that the version we're about to publish is going to
|
||||
work. At the end of this command, it should echo a `cd` command to run in your shell
|
||||
to switch to the installation directory. Something like this:
|
||||
|
||||
@@ -36,58 +27,21 @@ Try importing a profile from disk via the browse button and make sure it works.
|
||||
Next, try running `bin/cli.js dist/release/perf-vertx*`. This should immediately open
|
||||
speedscope in browser, and the perf-vertx file should load immediately.
|
||||
|
||||
If everything looks good, proceed to "Prepare the release".
|
||||
## Create & publish the new release
|
||||
|
||||
## Prepare the release
|
||||
Ensure you have the Github CLI tools installed and you're authenticated. Try running the following if you're unsure:
|
||||
|
||||
1. Update the version manually in package.json (we intentionally don't use the `npm version` command)
|
||||
2. Update CHANGELOG.md to indicate the changes that were made as part of this release
|
||||
3. Commit the changes with the version name as the commit message, e.g. `git commit -m 0.6.0`
|
||||
4. `git tag` the release. We use tags like `v0.6.0`, e.g. `git tag v0.6.0`
|
||||
5. `git push && git push --tags`
|
||||
gh auth status
|
||||
npm whoami
|
||||
|
||||
## Publish to npm
|
||||
Once ready to publish, run:
|
||||
|
||||
Assuming everything went well in the previous two phases, publishing should just be
|
||||
a matter of running `npm publish`.
|
||||
scripts/publish-and-deploy.sh
|
||||
|
||||
### Verifying the publish
|
||||
## Verifying the release
|
||||
|
||||
To verify that the publish was successful, run `npm install -g speedscope`.
|
||||
To verify that the npm publish was successful, run `npm install -g speedscope`.
|
||||
Try `speedscope`, which should open speedscope in browser.
|
||||
Try `speedscope sample/profiles/stackcollapse/simple.txt`, which should immediately load the profile.
|
||||
|
||||
## Deploying the website
|
||||
|
||||
This step must follow the "Publish to npm" step, since it uses assets from
|
||||
the npm publish.
|
||||
|
||||
https://www.speedscope.app/ is hosted on GitHub pages, and is published via pushing
|
||||
to the `gh-pages` branch. The `gh-pages` branch has totally different contents than
|
||||
other branches of this repository: https://github.com/jlfwong/speedscope/tree/gh-pages.
|
||||
|
||||
It's populated by a deploy script which is invoked by running `npm run deploy` script. This populate a directory with assets pulled from npm, and
|
||||
boot a local server for you to test the compiled assets. Please do not skip
|
||||
the manual testing in this step.
|
||||
|
||||
If everything looks good, you should be able to hit Ctrl+C, and you should see this prompt:
|
||||
|
||||
```
|
||||
Commit release? [yes/no]:
|
||||
```
|
||||
|
||||
If everything looks good, type `yes` then enter. This will commit to the `gh-pages` branch, and the site should automatically deploy shortly after.
|
||||
|
||||
To check if a deploy has happened, you can check https://www.speedscope.app/release.txt
|
||||
which includes the version, the date, and the commit of the deploy.
|
||||
|
||||
## Upload a release to GitHub
|
||||
|
||||
This step must follow the "Publish to npm" step, since it uses assets from
|
||||
the npm publish.
|
||||
|
||||
To make a zipfile suitable for uploading to GitHub as a release, run `scripts/prepare-zip-file.sh`.
|
||||
|
||||
Once that's done, you should have a zip file in `dist/release/`
|
||||
|
||||
Upload that file along with changelog notes to https://github.com/jlfwong/speedscope/releases/new
|
||||
To verify the website has finished deploying, check the version number shown in the console of https://www.speedscope.app/
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.15.0",
|
||||
"version": "1.16.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "speedscope",
|
||||
"version": "1.15.0",
|
||||
"version": "1.16.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"open": "7.2.0"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.15.0",
|
||||
"version": "1.16.0",
|
||||
"description": "",
|
||||
"repository": "jlfwong/speedscope",
|
||||
"main": "index.js",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
# callgrind format
|
||||
events: Instructions
|
||||
|
||||
fl=alpha.c
|
||||
fn=alpha
|
||||
1 10
|
||||
cfl=beta.c
|
||||
cfn=beta
|
||||
calls=1 1
|
||||
1 10
|
||||
cfn=gamma
|
||||
calls=1 1
|
||||
1 10
|
||||
cfn=delta
|
||||
calls=1 1
|
||||
1 20
|
||||
|
||||
fn=delta
|
||||
1 10
|
||||
cfn=gamma
|
||||
calls=1 1
|
||||
1 10
|
||||
|
||||
fn=gamma
|
||||
1 10
|
||||
cfl=
|
||||
|
||||
fl=beta.c
|
||||
fn=beta
|
||||
1 10
|
||||
@@ -18,7 +18,7 @@ calls=3 51
|
||||
16 400 3000
|
||||
|
||||
fn=(2)
|
||||
51 100 4000
|
||||
51 100 15000
|
||||
cfi=(2)
|
||||
cfn=(3)
|
||||
calls=2 20
|
||||
@@ -26,4 +26,4 @@ calls=2 20
|
||||
|
||||
fl=(2)
|
||||
fn=(3)
|
||||
20 700 6000
|
||||
20 700 8000
|
||||
@@ -0,0 +1,24 @@
|
||||
# callgrind format
|
||||
events: Instructions
|
||||
|
||||
fl=file1.c
|
||||
fn=main
|
||||
16 20
|
||||
cfn=func1
|
||||
calls=1 50
|
||||
* 400
|
||||
cfi=file2.c
|
||||
cfn=func2
|
||||
calls=3 20
|
||||
* *
|
||||
|
||||
fn=func1
|
||||
+35 -300
|
||||
cfi=file2.c
|
||||
cfn=func2
|
||||
calls=2 20
|
||||
* 300
|
||||
|
||||
fl=file2.c
|
||||
fn=func2
|
||||
-31 +400
|
||||
@@ -0,0 +1,16 @@
|
||||
Script_abc_example_quest log opened (PC)
|
||||
500:PUSH:3053:1:abcExampleQuest (24021278):abc_example_quest..exampleFunction1
|
||||
1500:POP:3053:1:abcExampleQuest (24021278):abc_example_quest..exampleFunction1
|
||||
1700:PUSH:3053:2:abcExampleQuest (24021278):abc_example_quest..exampleFunction2
|
||||
1750:POP:3053:2:abcExampleQuest (24021278):abc_example_quest..exampleFunction2
|
||||
2000:PUSH:3208:2:abcExampleQuest (24021278):abc_example_quest..exampleFunction3
|
||||
2000:PUSH:3053:3:None:abc_example_quest..exampleFunction4
|
||||
2000:POP:3208:2:abcExampleQuest (24021278):abc_example_quest..exampleFunction3
|
||||
2000:POP:3053:3:None:abc_example_quest..exampleFunction4
|
||||
2000:PUSH:3947:1:None:abc_example_quest..exampleFunction5
|
||||
2250:PUSH:3949:1:None:abc_example_quest..exampleFunction6
|
||||
2500:POP:3949:1:None:abc_example_quest..exampleFunction6
|
||||
3000:POP:3947:1:None:abc_example_quest..exampleFunction5
|
||||
3450:PUSH:3947:1:abcExampleQuest (24021278):abc_example_quest..exampleFunction1
|
||||
3500:POP:3947:1:abcExampleQuest (24021278):abc_example_quest..exampleFunction1
|
||||
Log closed
|
||||
@@ -0,0 +1,24 @@
|
||||
Stack_3185 log opened (PC)
|
||||
50002:START:3185
|
||||
50002:POP:3185:3:None:Debug..StartStackProfiling
|
||||
50002:QUEUE_PUSH:3185:3: (00018A56):Location.??.GetFormID
|
||||
50018:PUSH:3185:3: (00018A56):Form..GetFormID
|
||||
50018:POP:3185:3: (00018A56):Form..GetFormID
|
||||
50018:PUSH:3185:3:None:abc_example_mod_quest..exampleFunction1
|
||||
50018:QUEUE_PUSH:3185:4: (00018A56):Location.??.GetFormID
|
||||
50035:PUSH:3185:4: (00018A56):Form..GetFormID
|
||||
50035:POP:3185:4: (00018A56):Form..GetFormID
|
||||
50035:PUSH:3185:4:None:Game..GetModName
|
||||
50035:POP:3185:4:None:Game..GetModName
|
||||
50035:POP:3185:3:None:abc_example_mod_quest..exampleFunction1
|
||||
50035:POP:3185:2:None:abc_example_mod_quest..exampleFunction2
|
||||
50035:QUEUE_PUSH:3185:2:WhiterunPLainsDistrict03 (0001A27A):Cell.??.IsInterior
|
||||
50051:PUSH:3185:2:WhiterunPLainsDistrict03 (0001A27A):Cell..IsInterior
|
||||
50051:POP:3185:2:WhiterunPLainsDistrict03 (0001A27A):Cell..IsInterior
|
||||
50051:POP:3185:1:abcExampleModQuest (24021278):abc_example_mod_quest..exampleFunction3
|
||||
50051:QUEUE_PUSH:3185:1:None:utility.??.WaitMenuMode
|
||||
50068:PUSH:3185:1:None:utility..WaitMenuMode
|
||||
50602:POP:3185:1:None:utility..WaitMenuMode
|
||||
50602:QUEUE_POP:3185:0:None:abc_example_mod_effect..OnEffectStart
|
||||
50619:POP:3185:0:None:abc_example_mod_effect..OnEffectStart
|
||||
Log closed
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,6 +5,7 @@ def a
|
||||
for i in 0..100 do
|
||||
b
|
||||
c
|
||||
e
|
||||
end
|
||||
end
|
||||
|
||||
@@ -28,8 +29,13 @@ def d
|
||||
prod
|
||||
end
|
||||
|
||||
profile = StackProf.run(mode: :wall, raw: true) do
|
||||
def e
|
||||
sleep 0.05
|
||||
end
|
||||
|
||||
mode = (ARGV[0] || :wall).to_sym
|
||||
profile = StackProf.run(mode: mode, raw: true) do
|
||||
a
|
||||
end
|
||||
|
||||
puts JSON.generate(profile)
|
||||
puts JSON.generate(profile)
|
||||
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Print changes since the last tagged release in a format to match CHANGELOG.md
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <version>"
|
||||
echo "e.g. $0 1.15.2"
|
||||
exit 1
|
||||
fi
|
||||
version="$1"
|
||||
|
||||
|
||||
# Get the most recent tagged commit that is an ancestor of HEAD
|
||||
tagged_commit=$(git log --simplify-by-decoration --oneline --decorate | grep -E '^\w+ \(tag: .+\) .+$' | head -n1 | cut -d' ' -f 1)
|
||||
|
||||
gitlog=$(git log --graph --pretty=format:"%s" --abbrev-commit "$tagged_commit"..HEAD)
|
||||
|
||||
version="$1"
|
||||
|
||||
current_date=$(date +%Y-%m-%d)
|
||||
echo "## [$version] - $current_date"
|
||||
echo
|
||||
|
||||
while IFS= read line; do
|
||||
message=$(echo "$line" | sed 's/^* //g')
|
||||
message_without_pr_num=$(echo "$message" | sed 's/ (#[0-9][0-9]*)//g')
|
||||
|
||||
pr_number=$(echo "$message" | grep -Eo '#[0-9]+' | grep -Eo '[0-9]+'; true)
|
||||
|
||||
if [[ -n "$pr_number" ]]; then
|
||||
author=$(gh pr view $pr_number --json author -q ".author.login")
|
||||
pr_link="https://github.com/jlfwong/speedscope/pull/$pr_number"
|
||||
echo "- $message_without_pr_num [[#$pr_number]($pr_link)] (by @$author)"
|
||||
else
|
||||
echo "- $message_without_pr_num"
|
||||
fi
|
||||
done <<< "$gitlog"
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Run the full release process. This means...
|
||||
# - Bumping the version in package.json
|
||||
# - Updating the changelog
|
||||
# - Commiting and tagging the release
|
||||
# - Pushing to Github
|
||||
# - Publishing a new version to npm
|
||||
# - Deploying the website
|
||||
# - Create a new release in Github with the zip-file standalone version
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: $0 <minor | patch | version>"
|
||||
echo "e.g. $0 patch"
|
||||
exit 1
|
||||
fi
|
||||
version_arg="$1"
|
||||
|
||||
# Bump versions in package.json and package-lock.json, but don't commit or make tags yet
|
||||
version=$(npm version "$version_arg" --no-git-tag-version --no-commit-hooks | sed 's/^v//g')
|
||||
tagname="v$version"
|
||||
|
||||
script_dir=$(dirname "$0")
|
||||
|
||||
# Prepend the changelog update to CHANGELOG.md
|
||||
changelog_update=$("$script_dir/print-changelog-update.sh" "$version")
|
||||
|
||||
echo -e "$changelog_update\n" > CHANGELOG.md.new
|
||||
cat CHANGELOG.md >> CHANGELOG.md.new
|
||||
mv CHANGELOG.md.new CHANGELOG.md
|
||||
|
||||
# Commit and tag the release
|
||||
git add CHANGELOG.md package.json package-lock.json
|
||||
git commit -m "$version"
|
||||
git tag "$tagname"
|
||||
|
||||
# Push to Github
|
||||
git push
|
||||
git push --tags
|
||||
|
||||
# Publish to npm
|
||||
npm publish
|
||||
|
||||
# Create a new release on Github
|
||||
"$script_dir/prepare-zip-file.sh"
|
||||
gh release create "$tagname" --title "$tagname" --notes "$changelog_update" --attach "dist/release/speedscope-$version.zip"
|
||||
|
||||
# Deploy the website
|
||||
npm run deploy
|
||||
@@ -41,6 +41,61 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromCallgrind cfn reset 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "alpha.c",
|
||||
"key": "alpha.c:alpha",
|
||||
"line": undefined,
|
||||
"name": "alpha",
|
||||
"selfWeight": 10,
|
||||
"totalWeight": 50,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "beta.c",
|
||||
"key": "beta.c:beta",
|
||||
"line": undefined,
|
||||
"name": "beta",
|
||||
"selfWeight": 10,
|
||||
"totalWeight": 10,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "alpha.c",
|
||||
"key": "alpha.c:gamma",
|
||||
"line": undefined,
|
||||
"name": "gamma",
|
||||
"selfWeight": 20,
|
||||
"totalWeight": 20,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "alpha.c",
|
||||
"key": "alpha.c:delta",
|
||||
"line": undefined,
|
||||
"name": "delta",
|
||||
"selfWeight": 10,
|
||||
"totalWeight": 20,
|
||||
},
|
||||
],
|
||||
"name": "callgrind.cfn-reset.log -- Instructions",
|
||||
"stacks": Array [
|
||||
"alpha;beta 10",
|
||||
"alpha;gamma 10",
|
||||
"alpha;delta;gamma 10",
|
||||
"alpha;delta 10",
|
||||
"alpha 10",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromCallgrind cfn reset: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromCallgrind cfn reset: profileGroup.name 1`] = `"callgrind.cfn-reset.log"`;
|
||||
|
||||
exports[`importFromCallgrind multiple event types 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -100,7 +155,7 @@ Object {
|
||||
"key": "file1.c:func1",
|
||||
"line": undefined,
|
||||
"name": "func1",
|
||||
"selfWeight": 8888.888888888889,
|
||||
"selfWeight": 15000,
|
||||
"totalWeight": 20000,
|
||||
},
|
||||
Frame {
|
||||
@@ -109,14 +164,14 @@ Object {
|
||||
"key": "file2.c:func2",
|
||||
"line": undefined,
|
||||
"name": "func2",
|
||||
"selfWeight": 14111.111111111111,
|
||||
"totalWeight": 14111.111111111111,
|
||||
"selfWeight": 8000,
|
||||
"totalWeight": 8000,
|
||||
},
|
||||
],
|
||||
"name": "callgrind.multiple-event-types.log -- Memory",
|
||||
"stacks": Array [
|
||||
"main;func1;func2 10.85 KB",
|
||||
"main;func1 8.68 KB",
|
||||
"main;func1;func2 4.88 KB",
|
||||
"main;func1 14.65 KB",
|
||||
"main;func2 2.93 KB",
|
||||
"main 14.65 KB",
|
||||
],
|
||||
@@ -172,6 +227,51 @@ exports[`importFromCallgrind name compression: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromCallgrind name compression: profileGroup.name 1`] = `"callgrind.name-compression.log"`;
|
||||
|
||||
exports[`importFromCallgrind subposition compression 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "file1.c",
|
||||
"key": "file1.c:main",
|
||||
"line": undefined,
|
||||
"name": "main",
|
||||
"selfWeight": 20,
|
||||
"totalWeight": 820,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "file1.c",
|
||||
"key": "file1.c:func1",
|
||||
"line": undefined,
|
||||
"name": "func1",
|
||||
"selfWeight": 100,
|
||||
"totalWeight": 400,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "file2.c",
|
||||
"key": "file2.c:func2",
|
||||
"line": undefined,
|
||||
"name": "func2",
|
||||
"selfWeight": 700,
|
||||
"totalWeight": 700,
|
||||
},
|
||||
],
|
||||
"name": "callgrind.subposition-compression.log -- Instructions",
|
||||
"stacks": Array [
|
||||
"main;func1;func2 300",
|
||||
"main;func1 100",
|
||||
"main;func2 400",
|
||||
"main 20",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromCallgrind subposition compression: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromCallgrind subposition compression: profileGroup.name 1`] = `"callgrind.subposition-compression.log"`;
|
||||
|
||||
exports[`importFromCallgrind: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromCallgrind: profileGroup.name 1`] = `"callgrind.example.log"`;
|
||||
|
||||
@@ -515,6 +515,192 @@ exports[`importFromChromeTimeline Chrome 69: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromChromeTimeline Chrome 69: profileGroup.name 1`] = `"simple.json"`;
|
||||
|
||||
exports[`importFromChromeTimeline Chrome 116 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "(program):undefined:undefined:undefined",
|
||||
"line": undefined,
|
||||
"name": "(program)",
|
||||
"selfWeight": 9312,
|
||||
"totalWeight": 9312,
|
||||
},
|
||||
Frame {
|
||||
"col": 1,
|
||||
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "(anonymous simple.js:1):file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:1:1",
|
||||
"line": 1,
|
||||
"name": "(anonymous simple.js:1)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 25866,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "alpha:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:1:15",
|
||||
"line": 1,
|
||||
"name": "alpha",
|
||||
"selfWeight": 426,
|
||||
"totalWeight": 25866,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "beta:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:8:14",
|
||||
"line": 8,
|
||||
"name": "beta",
|
||||
"selfWeight": 8028,
|
||||
"totalWeight": 12703,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "gamma:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:20:15",
|
||||
"line": 20,
|
||||
"name": "gamma",
|
||||
"selfWeight": 8593,
|
||||
"totalWeight": 8593,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "delta:file:///Users/jlfwong/code/speedscope/sample/programs/javascript/simple.js:14:15",
|
||||
"line": 14,
|
||||
"name": "delta",
|
||||
"selfWeight": 8169,
|
||||
"totalWeight": 12737,
|
||||
},
|
||||
],
|
||||
"name": "Trace-20230603T221323.json",
|
||||
"stacks": Array [
|
||||
" 4.39ms",
|
||||
"(program) 7.71ms",
|
||||
" 6.51ms",
|
||||
"(program) 267.00µs",
|
||||
" 122.00µs",
|
||||
"(program) 338.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 297.00µs",
|
||||
"(anonymous simple.js:1);alpha 155.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 144.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 115.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 145.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 651.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 267.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 351.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 603.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 132.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 259.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 254.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 256.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 258.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 128.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 107.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 134.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 132.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 241.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 128.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 259.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 131.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 131.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 133.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 255.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 250.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 137.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 137.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 126.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 116.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 540.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 107.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 108.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 118.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 134.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 139.00µs",
|
||||
"(anonymous simple.js:1);alpha 134.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 135.00µs",
|
||||
"(anonymous simple.js:1);alpha 137.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 275.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;gamma 110.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta;gamma 262.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 246.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 259.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 241.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 611.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 133.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 354.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 226.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 226.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 106.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 125.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 368.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 496.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 107.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 387.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 258.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 239.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 446.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 494.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 132.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 264.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 245.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 260.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 128.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 258.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 258.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 129.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 260.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 130.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 128.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 275.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 241.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 258.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 257.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 258.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 137.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 405.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 937.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 269.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 134.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 269.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 136.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 272.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 133.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 542.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 945.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 270.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 406.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 409.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 140.00µs",
|
||||
"(anonymous simple.js:1);alpha;beta 135.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta 173.00µs",
|
||||
"(anonymous simple.js:1);alpha;delta;(program) 650.00µs",
|
||||
" 211.00µs",
|
||||
"(program) 348.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromChromeTimeline Chrome 116: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromChromeTimeline Chrome 116: profileGroup.name 1`] = `"Trace-20230603T221323.json"`;
|
||||
|
||||
exports[`importFromChromeTimeline Workers Chrome 66 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importFromPapyrus script profile 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "STACK 3053",
|
||||
"line": undefined,
|
||||
"name": "STACK 3053",
|
||||
"selfWeight": 200,
|
||||
"totalWeight": 1250,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_quest..exampleFunction1",
|
||||
"line": undefined,
|
||||
"name": "abc_example_quest..exampleFunction1",
|
||||
"selfWeight": 1050,
|
||||
"totalWeight": 1050,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_quest..exampleFunction2",
|
||||
"line": undefined,
|
||||
"name": "abc_example_quest..exampleFunction2",
|
||||
"selfWeight": 50,
|
||||
"totalWeight": 50,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "STACK 3208",
|
||||
"line": undefined,
|
||||
"name": "STACK 3208",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_quest..exampleFunction3",
|
||||
"line": undefined,
|
||||
"name": "abc_example_quest..exampleFunction3",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_quest..exampleFunction4",
|
||||
"line": undefined,
|
||||
"name": "abc_example_quest..exampleFunction4",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "STACK 3947",
|
||||
"line": undefined,
|
||||
"name": "STACK 3947",
|
||||
"selfWeight": 450,
|
||||
"totalWeight": 1500,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_quest..exampleFunction5",
|
||||
"line": undefined,
|
||||
"name": "abc_example_quest..exampleFunction5",
|
||||
"selfWeight": 750,
|
||||
"totalWeight": 1000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "STACK 3949",
|
||||
"line": undefined,
|
||||
"name": "STACK 3949",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 250,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_quest..exampleFunction6",
|
||||
"line": undefined,
|
||||
"name": "abc_example_quest..exampleFunction6",
|
||||
"selfWeight": 250,
|
||||
"totalWeight": 250,
|
||||
},
|
||||
],
|
||||
"name": "script.log",
|
||||
"stacks": Array [
|
||||
"STACK 3053;abc_example_quest..exampleFunction1 1.00s",
|
||||
"STACK 3053 200.00ms",
|
||||
"STACK 3053;abc_example_quest..exampleFunction2 50.00ms",
|
||||
" 250.00ms",
|
||||
"STACK 3947;abc_example_quest..exampleFunction5 250.00ms",
|
||||
"STACK 3947;abc_example_quest..exampleFunction5;STACK 3949;abc_example_quest..exampleFunction6 250.00ms",
|
||||
"STACK 3947;abc_example_quest..exampleFunction5 500.00ms",
|
||||
"STACK 3947 450.00ms",
|
||||
"STACK 3947;abc_example_quest..exampleFunction1 50.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromPapyrus script profile: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromPapyrus script profile: profileGroup.name 1`] = `"script.log"`;
|
||||
|
||||
exports[`importFromPapyrus stack profile 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "STACK 3185",
|
||||
"line": undefined,
|
||||
"name": "STACK 3185",
|
||||
"selfWeight": 66,
|
||||
"totalWeight": 617,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "Debug..StartStackProfiling",
|
||||
"line": undefined,
|
||||
"name": "Debug..StartStackProfiling",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "Form..GetFormID",
|
||||
"line": undefined,
|
||||
"name": "Form..GetFormID",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "abc_example_mod_quest..exampleFunction1",
|
||||
"line": undefined,
|
||||
"name": "abc_example_mod_quest..exampleFunction1",
|
||||
"selfWeight": 17,
|
||||
"totalWeight": 17,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "Game..GetModName",
|
||||
"line": undefined,
|
||||
"name": "Game..GetModName",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "Cell..IsInterior",
|
||||
"line": undefined,
|
||||
"name": "Cell..IsInterior",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "utility..WaitMenuMode",
|
||||
"line": undefined,
|
||||
"name": "utility..WaitMenuMode",
|
||||
"selfWeight": 534,
|
||||
"totalWeight": 534,
|
||||
},
|
||||
],
|
||||
"name": "stack.log",
|
||||
"stacks": Array [
|
||||
"STACK 3185 16.00ms",
|
||||
"STACK 3185;abc_example_mod_quest..exampleFunction1 17.00ms",
|
||||
"STACK 3185 33.00ms",
|
||||
"STACK 3185;utility..WaitMenuMode 534.00ms",
|
||||
"STACK 3185 17.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromPapyrus stack profile: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromPapyrus stack profile: profileGroup.name 1`] = `"stack.log"`;
|
||||
@@ -7,239 +7,239 @@ Object {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.main:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 198,
|
||||
"name": "runtime.main",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 136,
|
||||
"totalWeight": 1360000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go",
|
||||
"key": "main.main:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0",
|
||||
"line": 0,
|
||||
"line": 49,
|
||||
"name": "main.main",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 136,
|
||||
"totalWeight": 1360000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go",
|
||||
"key": "main.delta:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0",
|
||||
"line": 0,
|
||||
"line": 28,
|
||||
"name": "main.delta",
|
||||
"selfWeight": 22,
|
||||
"totalWeight": 58,
|
||||
"selfWeight": 220000000,
|
||||
"totalWeight": 580000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go",
|
||||
"key": "main.beta:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0",
|
||||
"line": 0,
|
||||
"line": 18,
|
||||
"name": "main.beta",
|
||||
"selfWeight": 39,
|
||||
"totalWeight": 39,
|
||||
"selfWeight": 390000000,
|
||||
"totalWeight": 390000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go",
|
||||
"key": "main.alpha:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0",
|
||||
"line": 0,
|
||||
"line": 11,
|
||||
"name": "main.alpha",
|
||||
"selfWeight": 48,
|
||||
"totalWeight": 48,
|
||||
"selfWeight": 480000000,
|
||||
"totalWeight": 480000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/jlfwong/code/speedscope/sample/programs/go/simple.go",
|
||||
"key": "main.gamma:/Users/jlfwong/code/speedscope/sample/programs/go/simple.go:0",
|
||||
"line": 0,
|
||||
"line": 34,
|
||||
"name": "main.gamma",
|
||||
"selfWeight": 27,
|
||||
"totalWeight": 27,
|
||||
"selfWeight": 270000000,
|
||||
"totalWeight": 270000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s",
|
||||
"key": "runtime.morestack:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:0",
|
||||
"line": 0,
|
||||
"line": 480,
|
||||
"name": "runtime.morestack",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 11,
|
||||
"totalWeight": 110000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go",
|
||||
"key": "runtime.newstack:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/stack.go:0",
|
||||
"line": 0,
|
||||
"line": 957,
|
||||
"name": "runtime.newstack",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 11,
|
||||
"totalWeight": 110000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/duff_amd64.s",
|
||||
"key": "runtime.duffcopy:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/duff_amd64.s:0",
|
||||
"line": 0,
|
||||
"line": 412,
|
||||
"name": "runtime.duffcopy",
|
||||
"selfWeight": 11,
|
||||
"totalWeight": 11,
|
||||
"selfWeight": 110000000,
|
||||
"totalWeight": 110000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go",
|
||||
"key": "runtime.timerproc:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go:0",
|
||||
"line": 0,
|
||||
"line": 247,
|
||||
"name": "runtime.timerproc",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go",
|
||||
"key": "runtime.goroutineReady:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/time.go:0",
|
||||
"line": 0,
|
||||
"line": 125,
|
||||
"name": "runtime.goroutineReady",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.goready:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 301,
|
||||
"name": "runtime.goready",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s",
|
||||
"key": "runtime.systemstack:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/asm_amd64.s:0",
|
||||
"line": 0,
|
||||
"line": 409,
|
||||
"name": "runtime.systemstack",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.goready.func1:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 302,
|
||||
"name": "runtime.goready.func1",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.ready:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 608,
|
||||
"name": "runtime.ready",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.wakep:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 2083,
|
||||
"name": "runtime.wakep",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.startm:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 2017,
|
||||
"name": "runtime.startm",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/lock_sema.go",
|
||||
"key": "runtime.notewakeup:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/lock_sema.go:0",
|
||||
"line": 0,
|
||||
"line": 147,
|
||||
"name": "runtime.notewakeup",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go",
|
||||
"key": "runtime.semawakeup:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go:0",
|
||||
"line": 0,
|
||||
"line": 36,
|
||||
"name": "runtime.semawakeup",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go",
|
||||
"key": "runtime.mach_semrelease:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/os_darwin.go:0",
|
||||
"line": 0,
|
||||
"line": 465,
|
||||
"name": "runtime.mach_semrelease",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s",
|
||||
"key": "runtime.mach_semaphore_signal:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s:0",
|
||||
"line": 0,
|
||||
"line": 558,
|
||||
"name": "runtime.mach_semaphore_signal",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
"selfWeight": 10000000,
|
||||
"totalWeight": 10000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.mstart:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 1193,
|
||||
"name": "runtime.mstart",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 2,
|
||||
"totalWeight": 20000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.mstart1:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 1227,
|
||||
"name": "runtime.mstart1",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 2,
|
||||
"totalWeight": 20000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go",
|
||||
"key": "runtime.sysmon:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/proc.go:0",
|
||||
"line": 0,
|
||||
"line": 4221,
|
||||
"name": "runtime.sysmon",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 2,
|
||||
"totalWeight": 20000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s",
|
||||
"key": "runtime.usleep:/usr/local/Cellar/go/1.10.1/libexec/src/runtime/sys_darwin_amd64.s:0",
|
||||
"line": 0,
|
||||
"line": 418,
|
||||
"name": "runtime.usleep",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 2,
|
||||
"selfWeight": 20000000,
|
||||
"totalWeight": 20000000,
|
||||
},
|
||||
],
|
||||
"name": "simple.prof",
|
||||
"stacks": Array [
|
||||
"runtime.main;main.main;main.delta;main.beta 14",
|
||||
"runtime.main;main.main;main.alpha 26",
|
||||
"runtime.main;main.main;main.gamma 27",
|
||||
"runtime.morestack;runtime.newstack;runtime.duffcopy 11",
|
||||
"runtime.main;main.main;main.beta 25",
|
||||
"runtime.main;main.main;main.delta 22",
|
||||
"runtime.main;main.main;main.delta;main.alpha 22",
|
||||
"runtime.timerproc;runtime.goroutineReady;runtime.goready;runtime.systemstack;runtime.goready.func1;runtime.ready;runtime.wakep;runtime.startm;runtime.notewakeup;runtime.semawakeup;runtime.mach_semrelease;runtime.mach_semaphore_signal 1",
|
||||
"runtime.mstart;runtime.mstart1;runtime.sysmon;runtime.usleep 2",
|
||||
"runtime.main;main.main;main.delta;main.beta 140.00ms",
|
||||
"runtime.main;main.main;main.alpha 260.00ms",
|
||||
"runtime.main;main.main;main.gamma 270.00ms",
|
||||
"runtime.morestack;runtime.newstack;runtime.duffcopy 110.00ms",
|
||||
"runtime.main;main.main;main.beta 250.00ms",
|
||||
"runtime.main;main.main;main.delta 220.00ms",
|
||||
"runtime.main;main.main;main.delta;main.alpha 220.00ms",
|
||||
"runtime.timerproc;runtime.goroutineReady;runtime.goready;runtime.systemstack;runtime.goready.func1;runtime.ready;runtime.wakep;runtime.startm;runtime.notewakeup;runtime.semawakeup;runtime.mach_semrelease;runtime.mach_semaphore_signal 10.00ms",
|
||||
"runtime.mstart;runtime.mstart1;runtime.sysmon;runtime.usleep 20.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,5 +1,453 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importCpuProfileWithProperWeights importFromStackprof cpu mode snapshot 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "sample/programs/ruby/simple.rb",
|
||||
"key": 5352342240,
|
||||
"line": undefined,
|
||||
"name": "<main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 410000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 4530376200,
|
||||
"line": undefined,
|
||||
"name": "<main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 410000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 4530486680,
|
||||
"line": 37,
|
||||
"name": "block in <main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 410000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 5335911080,
|
||||
"line": 4,
|
||||
"name": "Object#a",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 410000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 5335911040,
|
||||
"line": 12,
|
||||
"name": "Object#b",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 154000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 5335909920,
|
||||
"line": 24,
|
||||
"name": "Object#d",
|
||||
"selfWeight": 331000,
|
||||
"totalWeight": 331000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 5335910560,
|
||||
"line": 18,
|
||||
"name": "Object#c",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 177000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/mcorrea/src/github.com/dalehamel/speedscope/sample/programs/ruby/simple.rb",
|
||||
"key": 5335909880,
|
||||
"line": 32,
|
||||
"name": "Object#e",
|
||||
"selfWeight": 79000,
|
||||
"totalWeight": 79000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "",
|
||||
"key": 1,
|
||||
"line": undefined,
|
||||
"name": "(garbage collection)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 79000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "",
|
||||
"key": 5,
|
||||
"line": undefined,
|
||||
"name": "(sweeping)",
|
||||
"selfWeight": 71000,
|
||||
"totalWeight": 71000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "",
|
||||
"key": 3,
|
||||
"line": undefined,
|
||||
"name": "(marking)",
|
||||
"selfWeight": 8000,
|
||||
"totalWeight": 8000,
|
||||
},
|
||||
],
|
||||
"name": "simple-cpu-stackprof.json",
|
||||
"stacks": Array [
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 5.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"(garbage collection);(sweeping) 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 5.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 5.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 4.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(marking) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 5.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 1.00ms",
|
||||
"(garbage collection);(sweeping) 2.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#e 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 4.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#b;Object#b;Object#d;Object#d 2.00ms",
|
||||
"(garbage collection);(sweeping) 1.00ms",
|
||||
"<main>;<main>;block in <main>;Object#a;Object#a;Object#c;Object#c;Object#d;Object#d 3.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importCpuProfileWithProperWeights importFromStackprof cpu mode snapshot: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importCpuProfileWithProperWeights importFromStackprof cpu mode snapshot: profileGroup.name 1`] = `"simple-cpu-stackprof.json"`;
|
||||
|
||||
exports[`importFromStackprof 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -1046,6 +1494,201 @@ exports[`importFromStackprof object mode: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromStackprof object mode: profileGroup.name 1`] = `"object-stackprof.json"`;
|
||||
|
||||
exports[`importFromStackprof when a profile has a frame with no name 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "../../alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4317728280,
|
||||
"line": undefined,
|
||||
"name": "<main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4376547240,
|
||||
"line": undefined,
|
||||
"name": "<main>",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4379035920,
|
||||
"line": null,
|
||||
"name": "StackProf.run",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4317464320,
|
||||
"line": 21,
|
||||
"name": "block in <main>",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 103,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4379033920,
|
||||
"line": 4,
|
||||
"name": "Object#a",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 102,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4317869400,
|
||||
"line": null,
|
||||
"name": "Range#each",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 102,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4379033880,
|
||||
"line": 11,
|
||||
"name": "Object#b",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4318054440,
|
||||
"line": null,
|
||||
"name": "Class#new",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "/Users/alex/src/github.com/alexcoco/speedscope/sample/programs/ruby/object.rb",
|
||||
"key": 4379033840,
|
||||
"line": 15,
|
||||
"name": "Object#c",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 95,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4317868920,
|
||||
"line": null,
|
||||
"name": "Range#to_a",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 37,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4379016640,
|
||||
"line": null,
|
||||
"name": "Enumerable#to_a",
|
||||
"selfWeight": 36,
|
||||
"totalWeight": 36,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<internal:array>",
|
||||
"key": 4317563560,
|
||||
"line": 60,
|
||||
"name": "Array#sample",
|
||||
"selfWeight": 20,
|
||||
"totalWeight": 20,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "<cfunc>",
|
||||
"key": 4317922760,
|
||||
"line": null,
|
||||
"name": "(unknown)",
|
||||
"selfWeight": 36,
|
||||
"totalWeight": 36,
|
||||
},
|
||||
],
|
||||
"name": "stackprof-last-frame-no-name.json",
|
||||
"stacks": Array [
|
||||
"<main>;<main>;StackProf.run;block in <main> 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b;Class#new 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 3",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b;Class#new 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#b;Class#new 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Range#to_a;Enumerable#to_a 2",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;Array#sample 1",
|
||||
"<main>;<main>;StackProf.run;block in <main>;Object#a;Range#each;Object#a;Object#c;Range#each;Object#c;(unknown) 2",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromStackprof when a profile has a frame with no name: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromStackprof when a profile has a frame with no name: profileGroup.name 1`] = `"stackprof-last-frame-no-name.json"`;
|
||||
|
||||
exports[`importFromStackprof: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromStackprof: profileGroup.name 1`] = `"simple-stackprof.json"`;
|
||||
|
||||
@@ -11,3 +11,11 @@ test('importFromCallgrind name compression', async () => {
|
||||
test('importFromCallgrind multiple event types', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/callgrind/callgrind.multiple-event-types.log')
|
||||
})
|
||||
|
||||
test('importFromCallgrind subposition compression', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/callgrind/callgrind.subposition-compression.log')
|
||||
})
|
||||
|
||||
test('importFromCallgrind cfn reset', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/callgrind/callgrind.cfn-reset.log')
|
||||
})
|
||||
|
||||
+169
-56
@@ -129,26 +129,6 @@ class CallGraph {
|
||||
}
|
||||
|
||||
toProfile(): Profile {
|
||||
// To convert a call graph into a profile, we first need to identify what
|
||||
// the "root weights" are. "root weights" are the total weight of each frame
|
||||
// while at the bottom of the call-stack. The majority of functions will have
|
||||
// zero weight while at the bottom of the call-stack, since most functions
|
||||
// are never at the bottom of the call-stack.
|
||||
const rootWeights = new Map<Frame, number>()
|
||||
for (let [frame, totalWeight] of this.totalWeights) {
|
||||
rootWeights.set(frame, totalWeight)
|
||||
}
|
||||
for (let [_, childMap] of this.childrenTotalWeights) {
|
||||
for (let [child, weight] of childMap) {
|
||||
rootWeights.set(child, getOrElse(rootWeights, child, () => weight) - weight)
|
||||
}
|
||||
}
|
||||
|
||||
let totalProfileWeight = 0
|
||||
for (let [_, rootWeight] of rootWeights) {
|
||||
totalProfileWeight += rootWeight
|
||||
}
|
||||
|
||||
const profile = new CallTreeProfileBuilder()
|
||||
|
||||
let unitMultiplier = 1
|
||||
@@ -170,7 +150,12 @@ class CallGraph {
|
||||
|
||||
const currentStack = new Set<Frame>()
|
||||
|
||||
const visit = (frame: Frame, callTreeWeight: number) => {
|
||||
let maxWeight = 0
|
||||
for (let [_, totalWeight] of this.totalWeights) {
|
||||
maxWeight = Math.max(maxWeight, totalWeight)
|
||||
}
|
||||
|
||||
const visit = (frame: Frame, subtreeTotalWeight: number) => {
|
||||
if (currentStack.has(frame)) {
|
||||
// Call-graphs are allowed to have cycles. Call-trees are not. In case
|
||||
// we run into a cycle, we'll just avoid recursing into the same subtree
|
||||
@@ -198,7 +183,7 @@ class CallGraph {
|
||||
// See the comment at the top of the file for an example where this
|
||||
// assumption can yield especially misleading results.
|
||||
|
||||
if (callTreeWeight < 1e-4 * totalProfileWeight) {
|
||||
if (subtreeTotalWeight < 1e-4 * maxWeight) {
|
||||
// This assumption about even distribution can cause us to generate a
|
||||
// call tree with dramatically more nodes than the call graph.
|
||||
//
|
||||
@@ -220,45 +205,113 @@ class CallGraph {
|
||||
// 1000*250=250,000 nodes in the resulting call graph.
|
||||
//
|
||||
// To mitigate this explosion of the # of nodes, we ignore subtrees
|
||||
// whose weights are less than 0.01% of the total weight of the profile.
|
||||
// whose weights are less than 0.01% of the heaviest node in the call
|
||||
// graph.
|
||||
return
|
||||
}
|
||||
|
||||
// totalWeightForFrame is the total weight for the given frame in the
|
||||
// entire call graph.
|
||||
const callGraphWeightForFrame = getOrElse(this.totalWeights, frame, () => 0)
|
||||
if (callGraphWeightForFrame === 0) {
|
||||
const totalWeightForFrameInCallgraph = getOrElse(this.totalWeights, frame, () => 0)
|
||||
if (totalWeightForFrameInCallgraph === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// This is the portion of the total time the given child spends within the
|
||||
// given parent that we'll attribute to this specific path in the call
|
||||
// tree.
|
||||
const ratio = callTreeWeight / callGraphWeightForFrame
|
||||
let selfWeightForNodeInCallTree = subtreeTotalWeight
|
||||
|
||||
let selfWeightForFrame = callGraphWeightForFrame
|
||||
|
||||
profile.enterFrame(frame, totalCumulative * unitMultiplier)
|
||||
profile.enterFrame(frame, Math.round(totalCumulative * unitMultiplier))
|
||||
|
||||
currentStack.add(frame)
|
||||
for (let [child, callGraphEdgeWeight] of this.childrenTotalWeights.get(frame) || []) {
|
||||
selfWeightForFrame -= callGraphEdgeWeight
|
||||
const childCallTreeWeight = callGraphEdgeWeight * ratio
|
||||
for (let [child, totalWeightAsChild] of this.childrenTotalWeights.get(frame) || []) {
|
||||
// To determine the weight of the child in the call tree, we look at the
|
||||
// weight of the child in the call graph relative to its parent.
|
||||
const childCallTreeWeight =
|
||||
subtreeTotalWeight * (totalWeightAsChild / totalWeightForFrameInCallgraph)
|
||||
|
||||
let prevTotalCumulative = totalCumulative
|
||||
visit(child, childCallTreeWeight)
|
||||
|
||||
// Even though we tried to add a child with total weight equal to
|
||||
// childCallTreeWeight, we might have failed for a variety of data
|
||||
// consistency reasons, or due to cycles.
|
||||
//
|
||||
// We want to avoid losing weight in the call tree by subtracting from
|
||||
// the self weight on the assumption it was added to the subtree, so we
|
||||
// only subtree from the self weight the amount that was *actually* used
|
||||
// by the subtree, rather than the amount we *intended* for it to use.
|
||||
const actualChildCallTreeWeight = totalCumulative - prevTotalCumulative
|
||||
selfWeightForNodeInCallTree -= actualChildCallTreeWeight
|
||||
}
|
||||
currentStack.delete(frame)
|
||||
|
||||
totalCumulative += selfWeightForFrame * ratio
|
||||
profile.leaveFrame(frame, totalCumulative * unitMultiplier)
|
||||
totalCumulative += selfWeightForNodeInCallTree
|
||||
profile.leaveFrame(frame, Math.round(totalCumulative * unitMultiplier))
|
||||
}
|
||||
|
||||
for (let [rootFrame, rootWeight] of rootWeights) {
|
||||
if (rootWeight <= 0) {
|
||||
continue
|
||||
// It's surprisingly hard to figure out which nodes in the call graph
|
||||
// constitute the root nodes of call trees.
|
||||
//
|
||||
// Here are a few intuitive options, and reasons why they're not always
|
||||
// correct or good.
|
||||
//
|
||||
// ## 1. Find nodes in the call graph that have no callers
|
||||
//
|
||||
// This is probably right 99% of the time in practice, but since the
|
||||
// callgrind is totally general, it's totally valid to have a file
|
||||
// representing a profile for the following code:
|
||||
//
|
||||
// function a() {
|
||||
// b()
|
||||
// }
|
||||
// function b() {
|
||||
// }
|
||||
// a()
|
||||
// b()
|
||||
//
|
||||
// In this case, even though b has a caller, some of the real calltree for
|
||||
// an execution trace of the program will have b on the top of the stack.
|
||||
//
|
||||
// ## 2. Find nodes in the call graph that still have weight if you
|
||||
// subtract all of the weight caused by callers.
|
||||
//
|
||||
// The callgraph format, in theory, provides inclusive times for every
|
||||
// function call. That means if you have a function `alpha` with a total
|
||||
// weight of 20, and its only in-edge in the call-graph has weight of 10,
|
||||
// that should indicate that `alpha` exists both as the root-node of a
|
||||
// calltree, and as a node in some other call-tree.
|
||||
//
|
||||
// In theory, you should be able to figure out the weight of it as a root
|
||||
// node by subtracting the weights of all the in-edges. In practice, real
|
||||
// callgrind files are inconsistent in how they do accounting for in-edges
|
||||
// where you end up in weird situations where the weight of in-edges
|
||||
// *exceeds* the weight of nodes (where the weight of a node is its
|
||||
// self-weight plus the weight of all its out-edges).
|
||||
//
|
||||
// ## 3. Find the heaviest node in the call graph, build its call-tree, and
|
||||
// decrease the weights of other nodes in the call graph while you
|
||||
// build the call tree. After you've done this, repeat with the new
|
||||
// heaviest.
|
||||
//
|
||||
// I think this version is probably fully correct, but the performance is
|
||||
// awful. The naive-version is O(n^2) because you have to re-determine which
|
||||
// node is the heaviest after each time you finish building a call-tree. You
|
||||
// can't just sort, because the relative ordering also changes with the
|
||||
// construction of each call tree.
|
||||
//
|
||||
// There's probably a clever solution here which puts all of the nodes into
|
||||
// a min-heap and then deletes and re-inserts nodes as their weights change,
|
||||
// but reasoning about the performance of that is a big pain in the butt.
|
||||
//
|
||||
// Despite not always being correct, I'm opting for option (1).
|
||||
|
||||
const rootNodes = new Set<Frame>(this.frameSet)
|
||||
|
||||
for (let [_, childMap] of this.childrenTotalWeights) {
|
||||
for (let [child, _] of childMap) {
|
||||
rootNodes.delete(child)
|
||||
}
|
||||
// If we've reached here, it means that the given root frame has some
|
||||
// weight while at the top of the call-stack.
|
||||
visit(rootFrame, rootWeight)
|
||||
}
|
||||
|
||||
for (let rootNode of rootNodes) {
|
||||
visit(rootNode, this.totalWeights.get(rootNode)!)
|
||||
}
|
||||
|
||||
return profile.build()
|
||||
@@ -293,7 +346,7 @@ class CallgrindParser {
|
||||
private savedFunctionNames: {[id: string]: string} = {}
|
||||
|
||||
constructor(contents: TextFileContent, private importedFileName: string) {
|
||||
this.lines = contents.splitLines()
|
||||
this.lines = [...contents.splitLines()]
|
||||
this.lineNum = 0
|
||||
}
|
||||
|
||||
@@ -344,7 +397,7 @@ class CallgrindParser {
|
||||
}
|
||||
|
||||
private calleeFrameInfo(): FrameInfo {
|
||||
const file = this.calleeFilename || '(unknown)'
|
||||
const file = this.calleeFilename || this.filename || '(unknown)'
|
||||
const name = this.calleeFunctionName || '(unknown)'
|
||||
const key = `${file}:${name}`
|
||||
return {key, name, file}
|
||||
@@ -384,10 +437,20 @@ class CallgrindParser {
|
||||
|
||||
switch (key) {
|
||||
case 'fe':
|
||||
case 'fi':
|
||||
case 'fi': {
|
||||
// fe/fi are used to indicate the source-file of a function definition
|
||||
// changed mid-definition. This is for inlined code, but doesn't
|
||||
// indicate that we've actually switched to referring to a different
|
||||
// function, so we mostly ignore it.
|
||||
//
|
||||
// We still need to do the parseNameWithCompression call in case a name
|
||||
// is defined and then referenced later on for name compression.
|
||||
this.parseNameWithCompression(value, this.savedFileNames)
|
||||
break
|
||||
}
|
||||
|
||||
case 'fl': {
|
||||
this.filename = this.parseNameWithCompression(value, this.savedFileNames)
|
||||
this.calleeFilename = this.filename
|
||||
break
|
||||
}
|
||||
|
||||
@@ -398,6 +461,8 @@ class CallgrindParser {
|
||||
|
||||
case 'cfi':
|
||||
case 'cfl': {
|
||||
// NOTE: unlike the fe/fi distinction described above, cfi and cfl are
|
||||
// interchangeable.
|
||||
this.calleeFilename = this.parseNameWithCompression(value, this.savedFileNames)
|
||||
break
|
||||
}
|
||||
@@ -413,6 +478,22 @@ class CallgrindParser {
|
||||
// since it'll just be copying the exact same frame over-and-over again,
|
||||
// but that might be better than ignoring it.
|
||||
this.parseCostLine(this.lines[this.lineNum++], 'child')
|
||||
|
||||
// This isn't specified anywhere in the spec, but empirically the and
|
||||
// "cfn" scope should only persist for a single "call".
|
||||
//
|
||||
// This seems to be what KCacheGrind does too:
|
||||
//
|
||||
// https://github.com/KDE/kcachegrind/blob/ea4314db2785cb8f279fe884ee7f82445642b692/libcore/cachegrindloader.cpp#L1259
|
||||
this.calleeFilename = null
|
||||
this.calleeFunctionName = null
|
||||
break
|
||||
}
|
||||
|
||||
case 'cob':
|
||||
case 'ob': {
|
||||
// We ignore these for now. They're valid lines, but we don't capture or
|
||||
// display information about them.
|
||||
break
|
||||
}
|
||||
|
||||
@@ -458,21 +539,52 @@ class CallgrindParser {
|
||||
return name
|
||||
}
|
||||
|
||||
private prevCostLineNumbers: number[] = []
|
||||
|
||||
private parseCostLine(line: string, costType: 'self' | 'child'): boolean {
|
||||
// TODO(jlfwong): Handle "Subposition compression"
|
||||
// TODO(jlfwong): Allow hexadecimal encoding
|
||||
|
||||
const parts = line.split(/\s+/)
|
||||
const nums: number[] = []
|
||||
for (let part of parts) {
|
||||
// As far as I can tell from the specification, the callgrind format does
|
||||
// not accept floating point numbers.
|
||||
const asNum = parseInt(part)
|
||||
if (isNaN(asNum)) {
|
||||
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const part = parts[i]
|
||||
|
||||
if (part.length === 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
nums.push(asNum)
|
||||
if (part === '*' || part[0] === '-' || part[1] === '+') {
|
||||
// This handles "Subposition compression"
|
||||
// See: https://valgrind.org/docs/manual/cl-format.html#cl-format.overview.compression2
|
||||
if (this.prevCostLineNumbers.length <= i) {
|
||||
throw new Error(
|
||||
`Line ${this.lineNum} has a subposition on column ${i} but ` +
|
||||
`previous cost line has only ${this.prevCostLineNumbers.length} ` +
|
||||
`columns. Line contents: ${line}`,
|
||||
)
|
||||
}
|
||||
const prevCostForSubposition = this.prevCostLineNumbers[i]
|
||||
if (part === '*') {
|
||||
nums.push(prevCostForSubposition)
|
||||
} else {
|
||||
// This handles both the '-' and '+' cases
|
||||
const offset = parseInt(part)
|
||||
if (isNaN(offset)) {
|
||||
throw new Error(
|
||||
`Line ${this.lineNum} has a subposition on column ${i} but ` +
|
||||
`the offset is not a number. Line contents: ${line}`,
|
||||
)
|
||||
}
|
||||
nums.push(prevCostForSubposition + offset)
|
||||
}
|
||||
} else {
|
||||
const asNum = parseInt(part)
|
||||
if (isNaN(asNum)) {
|
||||
return false
|
||||
}
|
||||
nums.push(asNum)
|
||||
}
|
||||
}
|
||||
|
||||
if (nums.length == 0) {
|
||||
@@ -506,6 +618,7 @@ class CallgrindParser {
|
||||
}
|
||||
}
|
||||
|
||||
this.prevCostLineNumbers = nums
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,3 +30,7 @@ test('importFromChromeTimeline Workers Chrome 66', async () => {
|
||||
test('importFromChromeTimeline Workers Chrome 70', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Chrome/70/worker.json')
|
||||
})
|
||||
|
||||
test('importFromChromeTimeline Chrome 116', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Chrome/116/Trace-20230603T221323.json')
|
||||
})
|
||||
|
||||
@@ -49,7 +49,7 @@ export interface CPUProfile {
|
||||
timeDeltas: number[]
|
||||
}
|
||||
|
||||
export function isChromeTimeline(rawProfile: any): boolean {
|
||||
export function isChromeTimeline(rawProfile: any): rawProfile is TimelineEvent[] {
|
||||
if (!Array.isArray(rawProfile)) return false
|
||||
if (rawProfile.length < 1) return false
|
||||
const first = rawProfile[0]
|
||||
@@ -63,6 +63,14 @@ export function isChromeTimeline(rawProfile: any): boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
export function isChromeTimelineObject(
|
||||
rawProfile: any,
|
||||
): rawProfile is {traceEvents: TimelineEvent[]} {
|
||||
// Starting with Chrome 114, the timeline format output by devtools is an object
|
||||
if (!('traceEvents' in rawProfile)) return false
|
||||
return isChromeTimeline(rawProfile.traceEvents)
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
importFromChromeTimeline,
|
||||
isChromeTimeline,
|
||||
importFromOldV8CPUProfile,
|
||||
isChromeTimelineObject,
|
||||
} from './chrome'
|
||||
import {importFromStackprof} from './stackprof'
|
||||
import {importFromInstrumentsDeepCopy, importFromInstrumentsTrace} from './instruments'
|
||||
@@ -22,6 +23,7 @@ import {decodeBase64} from '../lib/utils'
|
||||
import {importFromChromeHeapProfile} from './v8heapalloc'
|
||||
import {isTraceEventFormatted, importTraceEvents} from './trace-event'
|
||||
import {importFromCallgrind} from './callgrind'
|
||||
import {importFromPapyrus} from "./papyrus";
|
||||
|
||||
export async function importProfileGroupFromText(
|
||||
fileName: string,
|
||||
@@ -92,6 +94,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
if (fileName.endsWith('.speedscope.json')) {
|
||||
console.log('Importing as speedscope json file')
|
||||
return importSpeedscopeProfiles(contents.parseAsJSON())
|
||||
} else if (/Trace-\d{8}T\d{6}/.exec(fileName)) {
|
||||
console.log('Importing as Chrome Timeline Object')
|
||||
return importFromChromeTimeline(contents.parseAsJSON().traceEvents, fileName)
|
||||
} else if (fileName.endsWith('.chrome.json') || /Profile-\d{8}T\d{6}/.exec(fileName)) {
|
||||
console.log('Importing as Chrome Timeline')
|
||||
return importFromChromeTimeline(contents.parseAsJSON(), fileName)
|
||||
@@ -136,6 +141,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
} else if (isChromeTimeline(parsed)) {
|
||||
console.log('Importing as Chrome Timeline')
|
||||
return importFromChromeTimeline(parsed, fileName)
|
||||
} else if (isChromeTimelineObject(parsed)) {
|
||||
console.log('Importing as Chrome Timeline Object')
|
||||
return importFromChromeTimeline(parsed.traceEvents, fileName)
|
||||
} else if ('nodes' in parsed && 'samples' in parsed && 'timeDeltas' in parsed) {
|
||||
console.log('Importing as Chrome CPU Profile')
|
||||
return toGroup(importFromChromeCPUProfile(parsed))
|
||||
@@ -181,6 +189,11 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
return toGroup(importFromInstrumentsDeepCopy(contents))
|
||||
}
|
||||
|
||||
if (/^(Stack_|Script_|Obj_)\S+ log opened \(PC\)\n/.exec(contents.firstChunk())){
|
||||
console.log("Importing as Papyrus profile")
|
||||
return toGroup(importFromPapyrus(contents))
|
||||
}
|
||||
|
||||
const fromLinuxPerf = importFromLinuxPerf(contents)
|
||||
if (fromLinuxPerf) {
|
||||
console.log('Importing from linux perf script output')
|
||||
|
||||
@@ -14,7 +14,7 @@ import {FileSystemDirectoryEntry, FileSystemEntry, FileSystemFileEntry} from './
|
||||
import {MaybeCompressedDataReader, TextFileContent} from './utils'
|
||||
|
||||
function parseTSV<T>(contents: TextFileContent): T[] {
|
||||
const lines = contents.splitLines().map(l => l.split('\t'))
|
||||
const lines = [...contents.splitLines()].map(l => l.split('\t'))
|
||||
|
||||
const headerLine = lines.shift()
|
||||
if (!headerLine) return []
|
||||
|
||||
@@ -23,8 +23,21 @@ interface PerfEvent {
|
||||
stack: PerfStackFrame[]
|
||||
}
|
||||
|
||||
function parseEvent(rawEvent: string): PerfEvent | null {
|
||||
const lines = rawEvent.split('\n').filter(l => !/^\s*#/.exec(l))
|
||||
function* parseEvents(contents: TextFileContent): Generator<PerfEvent | null> {
|
||||
let buffer: string[] = []
|
||||
for (let line of contents.splitLines()) {
|
||||
if (line === '') {
|
||||
yield parseEvent(buffer)
|
||||
buffer = []
|
||||
} else buffer.push(line)
|
||||
}
|
||||
|
||||
if (buffer.length > 0) yield parseEvent(buffer)
|
||||
}
|
||||
|
||||
// rawEvent is splitted into lines
|
||||
function parseEvent(rawEvent: string[]): PerfEvent | null {
|
||||
const lines = rawEvent.filter(l => !/^\s*#/.exec(l))
|
||||
|
||||
const event: PerfEvent = {
|
||||
command: null,
|
||||
@@ -81,41 +94,12 @@ function parseEvent(rawEvent: string): PerfEvent | null {
|
||||
return event
|
||||
}
|
||||
|
||||
function splitBlocks(contents: TextFileContent): string[] {
|
||||
// In perf files, blocks are separated by '\n\n'. If our input was a simple
|
||||
// string, we could use str.split('\n\n'), but since we have a TextFileContent
|
||||
// object which may be backed by several strings, we can't easily split this
|
||||
// way.
|
||||
//
|
||||
// Instead, we'll split into lines, and then re-group runs of non-empty strings.
|
||||
const blocks: string[] = []
|
||||
let pending: string = ''
|
||||
for (let line of contents.splitLines()) {
|
||||
if (line === '') {
|
||||
if (pending.length > 0) {
|
||||
blocks.push(pending)
|
||||
}
|
||||
pending = line
|
||||
} else {
|
||||
if (pending.length > 0) {
|
||||
pending += '\n'
|
||||
}
|
||||
pending += line
|
||||
}
|
||||
}
|
||||
if (pending.length > 0) {
|
||||
blocks.push(pending)
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
export function importFromLinuxPerf(contents: TextFileContent): ProfileGroup | null {
|
||||
const profiles = new Map<string, StackListProfileBuilder>()
|
||||
|
||||
let eventType: string | null = null
|
||||
const events = splitBlocks(contents).map(parseEvent)
|
||||
|
||||
for (let event of events) {
|
||||
for (let event of parseEvents(contents)) {
|
||||
if (event == null) continue
|
||||
if (eventType != null && eventType != event.eventType) continue
|
||||
if (event.time == null) continue
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import {checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
test('importFromPapyrus script profile', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/papyrus/script.log')
|
||||
})
|
||||
|
||||
test('importFromPapyrus stack profile', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/papyrus/stack.log')
|
||||
})
|
||||
@@ -0,0 +1,187 @@
|
||||
// This importer is for Papyrus, a proprietary DSL written by Bethesda for Skyrim and FO4. It is used both for the base
|
||||
// games and for mods. You can find documentation (such as the language reference) here:
|
||||
// https://ck.uesp.net/wiki/Category:Papyrus
|
||||
//
|
||||
// For mod authors: you can find documentation on how to start profiling from the console here:
|
||||
// https://ck.uesp.net/wiki/StartPapyrusScriptProfile
|
||||
// and you can also start from your script:
|
||||
// https://ck.uesp.net/wiki/StartScriptProfiling_-_Debug
|
||||
// If you want to profile an entire mod, it is often helpful to use `StartFormProfile` on your "main quest". This will
|
||||
// then profile all scripts attached to that Form.
|
||||
//
|
||||
// Papyrus works with a queue system, because it is multithreaded, but only one thread can exist per script.
|
||||
// (And we can only profile one script at a time.) We parse most "QUEUE_PUSH" events, specifically those that come
|
||||
// directly before their corresponding "PUSH" event. Other "QUEUE_PUSH" (and all "QUEUE_POP") events come, as far as I
|
||||
// can tell, from Events and are thus asynchronous. They are ignored.
|
||||
//
|
||||
// Stack profiling also puts a "START" operation at the top and a "STOP" operation at the bottom of the file. These are
|
||||
// completely useless to us.
|
||||
//
|
||||
// Stack profiling also logs the Form a method is run on. For those that are not familiar with
|
||||
// Papyrus terminology, a "Form" is an instance of a type defined by a script. E.g. a quest is a form that extends
|
||||
// the "Quest" script, and thus it has certain methods, like "CompleteQuest()". This information would be useful
|
||||
// for Debugging, but for profiling, it would hinder meaningful output in left heavy mode.
|
||||
|
||||
import {CallTreeProfileBuilder, Frame, Profile} from '../lib/profile'
|
||||
import {KeyedSet, lastOf} from '../lib/utils'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
import {TextFileContent} from './utils'
|
||||
|
||||
type ParsedLine = {
|
||||
at: number
|
||||
event: string
|
||||
stackInt: number
|
||||
name: string
|
||||
}
|
||||
|
||||
export function importFromPapyrus(papyrusProfile: TextFileContent): Profile {
|
||||
const profile = new CallTreeProfileBuilder()
|
||||
profile.setValueFormatter(new TimeFormatter('milliseconds'))
|
||||
|
||||
const papyrusProfileLines = [...papyrusProfile.splitLines()].filter(
|
||||
line => !/^$|^Log closed$|log opened/.exec(line),
|
||||
)
|
||||
|
||||
let startValue = -1
|
||||
const firstLineParsed = parseLine(papyrusProfileLines[0])
|
||||
if (firstLineParsed === null) throw Error
|
||||
startValue = firstLineParsed.at
|
||||
const lastLine = lastOf(papyrusProfileLines)
|
||||
if (lastLine === null) throw Error
|
||||
const lastLineParsed = parseLine(lastLine)
|
||||
if (lastLineParsed === null) throw Error
|
||||
const endValue = lastLineParsed.at
|
||||
|
||||
const nameSet = new KeyedSet<Frame>()
|
||||
const frameStack: string[] = []
|
||||
let lastEventAt = 0
|
||||
|
||||
let lastQueueFrameName: string
|
||||
let lastQueueFrameAt: number = -1
|
||||
|
||||
function enterFrame(stackInt: number, at: number, frameName: string) {
|
||||
function enterFrameHelper(at: number, frameName: string) {
|
||||
frameStack.push(frameName)
|
||||
profile.enterFrame(Frame.getOrInsert(nameSet, {name: frameName, key: frameName}), at)
|
||||
lastEventAt = at
|
||||
}
|
||||
// Check if the last event was "QUEUE_PUSH"
|
||||
if (lastQueueFrameAt > -1) {
|
||||
lastQueueFrameAt = -1
|
||||
// If the queue from last event matches our current frame,
|
||||
if (lastQueueFrameName === frameName && lastQueueFrameAt >= lastEventAt) {
|
||||
// first enter the queue frame at its earlier time
|
||||
enterFrame(stackInt, lastQueueFrameAt, `QUEUE ${frameName}`)
|
||||
}
|
||||
}
|
||||
const stackFrameStr = `STACK ${stackInt}`
|
||||
// If the uppermost STACK frame on the frameStack isn't stackFrameStr
|
||||
if (
|
||||
[...frameStack].reverse().find(frameName => frameName.startsWith('STACK ')) !== stackFrameStr
|
||||
) {
|
||||
// If we're at the bottom of the frameStack, STACK frames are kept open as long as functions only run in that
|
||||
// specific stack and closed with the function's end if the next function runs on a different stack.
|
||||
if (frameStack.length === 1) leaveFrame(lastEventAt)
|
||||
enterFrameHelper(at, stackFrameStr)
|
||||
}
|
||||
enterFrameHelper(at, frameName)
|
||||
}
|
||||
|
||||
function leaveFrame(at: number) {
|
||||
const frame = frameStack.pop()
|
||||
if (frame === undefined) throw Error('Tried to leave frame when nothing was on stack.')
|
||||
profile.leaveFrame(Frame.getOrInsert(nameSet, {name: frame, key: frame}), at)
|
||||
let topOfStack = lastOf(frameStack)
|
||||
// Technically, the frame is popped from queue once it is pushed onto the stack (once we have "entered the frame")
|
||||
// but since we want to visualize meaningfully, we count from QUEUE_PUSH to POP and prefix with "QUEUE ".
|
||||
if (topOfStack !== null && topOfStack.startsWith('QUEUE ')) {
|
||||
leaveFrame(at)
|
||||
topOfStack = lastOf(frameStack)
|
||||
}
|
||||
if (frameStack.length > 1 && topOfStack !== null && topOfStack.startsWith('STACK ')) {
|
||||
leaveFrame(at)
|
||||
}
|
||||
lastEventAt = at
|
||||
}
|
||||
|
||||
function tryToLeaveFrame(stackInt: number, at: number, frameName: string) {
|
||||
if (lastOf(frameStack) === frameName) {
|
||||
leaveFrame(at)
|
||||
} else {
|
||||
if (lastEventAt === 0) {
|
||||
console.log(
|
||||
`Tried to leave frame "${frameName}" which was never entered. Assuming it has been running since the start.`,
|
||||
)
|
||||
enterFrame(stackInt, 0, frameName)
|
||||
leaveFrame(at)
|
||||
} else {
|
||||
console.log(
|
||||
`Tried to leave frame "${frameName}" which was never entered. Other events have happened since the start, ignoring line.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function parseLine(lineStr: string): ParsedLine | null {
|
||||
if (lineStr === undefined) throw Error('Probably tried to import empty file.')
|
||||
const lineArr = lineStr.split(':')
|
||||
if (lineArr.length < 3) return null
|
||||
if (startValue !== -1) {
|
||||
return {
|
||||
at: parseInt(lineArr[0]) - startValue,
|
||||
event: lineArr[1],
|
||||
stackInt: parseInt(lineArr[2]),
|
||||
name: lineArr[5],
|
||||
}
|
||||
} else {
|
||||
// When parsing the first line, we return an absolute `at` value to initialize `startValue`
|
||||
return {
|
||||
at: parseInt(lineArr[0]),
|
||||
event: lineArr[1],
|
||||
stackInt: parseInt(lineArr[2]),
|
||||
name: lineArr[5],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
papyrusProfileLines.forEach((lineStr, i, papyrusProfileLines) => {
|
||||
const parsedLine = parseLine(lineStr)
|
||||
if (parsedLine === null) return // continue
|
||||
if (parsedLine.event === 'PUSH') {
|
||||
enterFrame(parsedLine.stackInt, parsedLine.at, parsedLine.name)
|
||||
i += 1
|
||||
let parsedNextLine = parseLine(papyrusProfileLines[i])
|
||||
// Search all future events in the current event for one that leaves the current frame. If it exists, leave now.
|
||||
// This way, we avoid speedscope choking on the possibly wrong order of events. The changed order is still
|
||||
// functionally correct, as the function took less than a millisecond to execute, which is measured as 0 (ms).
|
||||
while (parsedNextLine !== null && parsedNextLine.at === parsedLine.at) {
|
||||
if (
|
||||
parsedNextLine.name === parsedLine.name &&
|
||||
parsedNextLine.stackInt === parsedLine.stackInt &&
|
||||
parsedNextLine.event === 'POP'
|
||||
) {
|
||||
tryToLeaveFrame(parsedNextLine.stackInt, parsedNextLine.at, parsedNextLine.name)
|
||||
// Delete the line that we successfully parsed and imported such that it is not processed twice
|
||||
papyrusProfileLines.splice(i, 1)
|
||||
parsedNextLine = null
|
||||
} else {
|
||||
i += 1
|
||||
if (i < papyrusProfileLines.length) parsedNextLine = parseLine(papyrusProfileLines[i])
|
||||
}
|
||||
}
|
||||
} else if (parsedLine.event === 'POP') {
|
||||
tryToLeaveFrame(parsedLine.stackInt, parsedLine.at, parsedLine.name)
|
||||
} else if (parsedLine.event === 'QUEUE_PUSH') {
|
||||
lastQueueFrameName = parsedLine.name.replace(/\?/g, '')
|
||||
lastQueueFrameAt = parsedLine.at
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
// Close frames that are still open
|
||||
while (frameStack.length > 0) {
|
||||
leaveFrame(endValue)
|
||||
}
|
||||
|
||||
return profile.build()
|
||||
}
|
||||
+27
-4
@@ -2,12 +2,32 @@ import {perftools} from './profile.proto.js'
|
||||
import {FrameInfo, StackListProfileBuilder, Profile} from '../lib/profile'
|
||||
import {lastOf} from '../lib/utils'
|
||||
import {TimeFormatter, ByteFormatter} from '../lib/value-formatters'
|
||||
import Long from 'long'
|
||||
|
||||
interface SampleType {
|
||||
type: string
|
||||
unit: string
|
||||
}
|
||||
|
||||
// Find the index of the SampleType which should be used as our default
|
||||
function getSampleTypeIndex(profile: perftools.profiles.Profile): number {
|
||||
const dflt = profile.defaultSampleType
|
||||
const sampleTypes = profile.sampleType
|
||||
const fallback = sampleTypes.length - 1
|
||||
|
||||
// string_table[0] will always be empty-string, so we can assume dflt === 0 is just the proto
|
||||
// empty-value, and means no defaultSampleType was specified.
|
||||
if (!dflt || !+dflt) {
|
||||
return fallback
|
||||
}
|
||||
|
||||
const idx = sampleTypes.findIndex(e => e.type === dflt)
|
||||
if (idx === -1) {
|
||||
return fallback
|
||||
}
|
||||
return idx
|
||||
}
|
||||
|
||||
export function importAsPprofProfile(rawProfile: ArrayBuffer): Profile | null {
|
||||
if (rawProfile.byteLength === 0) return null
|
||||
|
||||
@@ -81,7 +101,12 @@ export function importAsPprofProfile(rawProfile: ArrayBuffer): Profile | null {
|
||||
if (lastLine == null) return null
|
||||
|
||||
if (lastLine.functionId) {
|
||||
return frameInfoByFunctionID.get(i32(lastLine.functionId)) || null
|
||||
let funcFrame = frameInfoByFunctionID.get(i32(lastLine.functionId))
|
||||
const line = lastLine.line instanceof Long ? lastLine.line.toNumber() : lastLine.line
|
||||
if (line && line > 0 && funcFrame != null) {
|
||||
funcFrame.line = line
|
||||
}
|
||||
return funcFrame || null
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
@@ -103,9 +128,7 @@ export function importAsPprofProfile(rawProfile: ArrayBuffer): Profile | null {
|
||||
unit: (type.unit && stringVal(type.unit)) || 'count',
|
||||
}))
|
||||
|
||||
const sampleTypeIndex = protoProfile.defaultSampleType
|
||||
? +protoProfile.defaultSampleType
|
||||
: sampleTypes.length - 1
|
||||
const sampleTypeIndex = getSampleTypeIndex(protoProfile)
|
||||
const sampleType = sampleTypes[sampleTypeIndex]
|
||||
|
||||
const profileBuilder = new StackListProfileBuilder()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { readFileSync } from 'fs';
|
||||
import { importProfileGroupFromText } from '.'
|
||||
import {checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
test('importFromStackprof', async () => {
|
||||
@@ -7,3 +9,30 @@ test('importFromStackprof', async () => {
|
||||
test('importFromStackprof object mode', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackprof/object-stackprof.json')
|
||||
})
|
||||
|
||||
test('importFromStackprof when a profile has a frame with no name', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackprof/stackprof-last-frame-no-name.json')
|
||||
})
|
||||
|
||||
describe('importCpuProfileWithProperWeights', () => {
|
||||
test('importFromStackprof cpu mode snapshot', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackprof/simple-cpu-stackprof.json')
|
||||
})
|
||||
|
||||
test('uses samples count for weight when importing cpu profile', async () => {
|
||||
|
||||
const profileFile = readFileSync('./sample/profiles/stackprof/simple-cpu-stackprof.json')
|
||||
const profileGroup = await importProfileGroupFromText('simple-cpu-stackprof.json', profileFile.toString())
|
||||
expect(profileGroup).not.toBeNull()
|
||||
|
||||
if (profileGroup) {
|
||||
const profile = profileGroup.profiles[profileGroup.indexToView]
|
||||
expect(profile).not.toBeNull()
|
||||
|
||||
if (profile) {
|
||||
expect(profile.getWeightUnit()).toBe('microseconds')
|
||||
expect(profile.getTotalWeight()).toBe(489000)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
+28
-22
@@ -1,10 +1,10 @@
|
||||
// https://github.com/tmm1/stackprof
|
||||
|
||||
import {Profile, FrameInfo, StackListProfileBuilder} from '../lib/profile'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
import {RawValueFormatter, TimeFormatter} from '../lib/value-formatters'
|
||||
|
||||
interface StackprofFrame {
|
||||
name: string
|
||||
name?: string
|
||||
file?: string
|
||||
line?: number
|
||||
}
|
||||
@@ -15,14 +15,13 @@ export interface StackprofProfile {
|
||||
raw: number[]
|
||||
raw_timestamp_deltas: number[]
|
||||
samples: number
|
||||
interval: number
|
||||
}
|
||||
|
||||
export function importFromStackprof(stackprofProfile: StackprofProfile): Profile {
|
||||
const {frames, mode, raw, raw_timestamp_deltas, samples} = stackprofProfile
|
||||
const objectMode = mode == 'object'
|
||||
|
||||
const size = objectMode ? samples : stackprofProfile.raw_timestamp_deltas.reduce((a, b) => a + b, 0)
|
||||
const profile = new StackListProfileBuilder(size)
|
||||
const {frames, mode, raw, raw_timestamp_deltas, interval} = stackprofProfile
|
||||
const profile = new StackListProfileBuilder()
|
||||
profile.setValueFormatter(new TimeFormatter('microseconds')) // default to time format unless we're in object mode
|
||||
|
||||
let sampleIndex = 0
|
||||
|
||||
@@ -34,33 +33,40 @@ export function importFromStackprof(stackprofProfile: StackprofProfile): Profile
|
||||
let stack: FrameInfo[] = []
|
||||
for (let j = 0; j < stackHeight; j++) {
|
||||
const id = raw[i++]
|
||||
stack.push({
|
||||
let frameName = frames[id].name;
|
||||
if (frameName == null) {
|
||||
frameName = '(unknown)';
|
||||
}
|
||||
const frame = {
|
||||
key: id,
|
||||
...frames[id],
|
||||
})
|
||||
name: frameName,
|
||||
}
|
||||
stack.push(frame)
|
||||
}
|
||||
if (stack.length === 1 && stack[0].name === '(garbage collection)') {
|
||||
stack = prevStack.concat(stack)
|
||||
}
|
||||
const nSamples = raw[i++]
|
||||
|
||||
if (objectMode) {
|
||||
profile.appendSampleWithWeight(stack, nSamples)
|
||||
} else {
|
||||
let sampleDuration = 0
|
||||
for (let j = 0; j < nSamples; j++) {
|
||||
sampleDuration += raw_timestamp_deltas[sampleIndex++]
|
||||
}
|
||||
|
||||
profile.appendSampleWithWeight(stack, sampleDuration)
|
||||
switch (mode) {
|
||||
case 'object':
|
||||
profile.appendSampleWithWeight(stack, nSamples)
|
||||
profile.setValueFormatter(new RawValueFormatter())
|
||||
break
|
||||
case 'cpu':
|
||||
profile.appendSampleWithWeight(stack, nSamples * interval)
|
||||
break
|
||||
default:
|
||||
let sampleDuration = 0
|
||||
for (let j = 0; j < nSamples; j++) {
|
||||
sampleDuration += raw_timestamp_deltas[sampleIndex++]
|
||||
}
|
||||
profile.appendSampleWithWeight(stack, sampleDuration)
|
||||
}
|
||||
|
||||
prevStack = stack
|
||||
}
|
||||
|
||||
if (!objectMode) {
|
||||
profile.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
}
|
||||
|
||||
return profile.build()
|
||||
}
|
||||
|
||||
+20
-11
@@ -8,7 +8,7 @@ export interface ProfileDataSource {
|
||||
}
|
||||
|
||||
export interface TextFileContent {
|
||||
splitLines(): string[]
|
||||
splitLines(): Iterable<string>
|
||||
firstChunk(): string
|
||||
parseAsJSON(): any
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export interface TextFileContent {
|
||||
//
|
||||
// We provide a simple splitLines() which returns simple strings under the
|
||||
// assumption that most extremely large text profiles will be broken into many
|
||||
// lines. This isn't true in the general case, but will be true for most common
|
||||
// lines. This isn't true in the general case, but will be true for most common
|
||||
// large files.
|
||||
//
|
||||
// See: https://github.com/v8/v8/blob/8b663818fc311217c2cdaaab935f020578bfb7a8/src/objects/string.h#L479-L483
|
||||
@@ -151,17 +151,26 @@ export class BufferBackedTextFileContent implements TextFileContent {
|
||||
}
|
||||
}
|
||||
|
||||
splitLines(): string[] {
|
||||
let parts: string[] = this.chunks[0].split('\n')
|
||||
for (let i = 1; i < this.chunks.length; i++) {
|
||||
const chunkParts = this.chunks[i].split('\n')
|
||||
if (chunkParts.length === 0) continue
|
||||
if (parts.length > 0) {
|
||||
parts[parts.length - 1] += chunkParts.shift()
|
||||
splitLines(): Iterable<string> {
|
||||
const iterator = function* (this: BufferBackedTextFileContent) {
|
||||
let lineBuffer: string = ''
|
||||
for (let chunk of this.chunks) {
|
||||
const fragments = chunk.split('\n')
|
||||
for (let i = 0; i < fragments.length; i++) {
|
||||
if (i === 0) lineBuffer += fragments[i]
|
||||
else {
|
||||
yield lineBuffer
|
||||
lineBuffer = fragments[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
parts = parts.concat(chunkParts)
|
||||
|
||||
yield lineBuffer
|
||||
}
|
||||
|
||||
return {
|
||||
[Symbol.iterator]: iterator.bind(this),
|
||||
}
|
||||
return parts
|
||||
}
|
||||
|
||||
firstChunk(): string {
|
||||
|
||||
+5
-5
@@ -439,14 +439,13 @@ export class Profile {
|
||||
}
|
||||
|
||||
export class StackListProfileBuilder extends Profile {
|
||||
_appendSample(stack: FrameInfo[], weight: number, useAppendOrder: boolean) {
|
||||
_appendSample(stack: Frame[], weight: number, useAppendOrder: boolean) {
|
||||
if (isNaN(weight)) throw new Error('invalid weight')
|
||||
let node = useAppendOrder ? this.appendOrderCalltreeRoot : this.groupedCalltreeRoot
|
||||
|
||||
let framesInStack = new Set<Frame>()
|
||||
|
||||
for (let frameInfo of stack) {
|
||||
const frame = Frame.getOrInsert(this.frames, frameInfo)
|
||||
for (let frame of stack) {
|
||||
const last = useAppendOrder
|
||||
? lastOf(node.children)
|
||||
: node.children.find(c => c.frame === frame)
|
||||
@@ -500,8 +499,9 @@ export class StackListProfileBuilder extends Profile {
|
||||
throw new Error('Samples must have positive weights')
|
||||
}
|
||||
|
||||
this._appendSample(stack, weight, true)
|
||||
this._appendSample(stack, weight, false)
|
||||
const frames = stack.map(fr => Frame.getOrInsert(this.frames, fr))
|
||||
this._appendSample(frames, weight, true)
|
||||
this._appendSample(frames, weight, false)
|
||||
}
|
||||
|
||||
private pendingSample: {
|
||||
|
||||
@@ -43,8 +43,8 @@ export function buildTrimmedText(text: string, length: number): TrimmedTextResul
|
||||
|
||||
let prefixLength = Math.floor(length / 2)
|
||||
const suffixLength = length - prefixLength - 1
|
||||
const prefix = text.substr(0, prefixLength)
|
||||
const suffix = text.substr(text.length - suffixLength, suffixLength)
|
||||
const prefix = text.substring(0, prefixLength)
|
||||
const suffix = text.substring(text.length - suffixLength, text.length)
|
||||
const trimmedString = prefix + ELLIPSIS + suffix
|
||||
return {
|
||||
trimmedString,
|
||||
@@ -69,11 +69,11 @@ export function trimTextMid(
|
||||
0,
|
||||
text.length,
|
||||
n => {
|
||||
return cachedMeasureTextWidth(ctx, buildTrimmedText(text, n).trimmedString)
|
||||
return cachedMeasureTextWidth(ctx, buildTrimmedText(text, Math.floor(n)).trimmedString)
|
||||
},
|
||||
maxWidth,
|
||||
)
|
||||
return buildTrimmedText(text, lo)
|
||||
return buildTrimmedText(text, Math.floor(lo))
|
||||
}
|
||||
|
||||
enum IndexTypeInTrimmed {
|
||||
|
||||
+10
-3
@@ -247,11 +247,18 @@ test('BufferBackedTextFileContent.firstChunk', async () => {
|
||||
})
|
||||
|
||||
test('BufferBackedTextFileContent.splitLines', async () => {
|
||||
await withMockedFileChunkSizeForTests(2, () => {
|
||||
const str = 'may\nyour\nrope\nbe\nlong'
|
||||
function testWithString(str: string) {
|
||||
const buffer = new TextEncoder().encode(str).buffer
|
||||
const content = new BufferBackedTextFileContent(buffer)
|
||||
expect(content.splitLines()).toEqual(['may', 'your', 'rope', 'be', 'long'])
|
||||
expect([...content.splitLines()]).toEqual(str.split('\n'))
|
||||
}
|
||||
|
||||
await withMockedFileChunkSizeForTests(2, () => {
|
||||
testWithString('may\nyour\nrope\nbe\nlong')
|
||||
testWithString('one-single-line')
|
||||
testWithString('multiple\n\nnew\n\nlines')
|
||||
testWithString('end-with-new-line\n')
|
||||
testWithString('')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user