Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c04a148518 | ||
|
|
103e441e27 | ||
|
|
911feb609b | ||
|
|
c7be11d4e0 | ||
|
|
146477a850 | ||
|
|
d36c3a5442 | ||
|
|
e468c60229 | ||
|
|
d69f3d0eec | ||
|
|
25f671e9d8 | ||
|
|
0121cf9342 | ||
|
|
68fd88ceaf | ||
|
|
a6d700194f | ||
|
|
a3c0b15935 | ||
|
|
e9a17d5d14 | ||
|
|
3f3da22853 | ||
|
|
bea0ef6913 | ||
|
|
4feb1e564d | ||
|
|
88f4fe6105 | ||
|
|
60f1812e51 | ||
|
|
1717fecafb | ||
|
|
c296f530c7 | ||
|
|
8e0fa58d65 | ||
|
|
b21480494e | ||
|
|
dfd3a0dfb3 | ||
|
|
ac4a015559 | ||
|
|
de17f128d0 | ||
|
|
304ccf33ab | ||
|
|
650e505b55 | ||
|
|
8dad28e5e2 | ||
|
|
f62519ab69 | ||
|
|
984bf1296a | ||
|
|
26884c116c | ||
|
|
bb063e49e3 | ||
|
|
693545b77a | ||
|
|
b3b4b1492a | ||
|
|
9cdceede15 | ||
|
|
741fdeb427 | ||
|
|
e9133be353 | ||
|
|
fcc1fa5689 | ||
|
|
0414c2f617 | ||
|
|
f23f65b3af | ||
|
|
8da9088ec1 | ||
|
|
81a6f29ad1 | ||
|
|
263f7d513e | ||
|
|
1bce806933 | ||
|
|
6493c5f66f | ||
|
|
639dae322b |
@@ -9,6 +9,7 @@ module.exports = {
|
||||
plugins: ['prettier', '@typescript-eslint', 'react-hooks'],
|
||||
rules: {
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'prettier/prettier': 'error',
|
||||
'react-hooks/rules-of-hooks': 'error',
|
||||
'react-hooks/exhaustive-deps': [
|
||||
'error',
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x]
|
||||
node-version: [18.x, 20.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ node_modules
|
||||
dist
|
||||
.idea
|
||||
coverage
|
||||
.vscode
|
||||
.vscode
|
||||
@@ -1,3 +1,73 @@
|
||||
## [1.21.2] - 2025-01-15
|
||||
|
||||
- Switch from parcel to esbuild [[#432](https://github.com/jlfwong/speedscope/pull/432)] (by @jlfwong)
|
||||
- Revert "Upgrade to parcel 2.13.3" [[#492](https://github.com/jlfwong/speedscope/pull/492)] (by @jlfwong)
|
||||
- Upgrade to parcel 2.13.3 [[#492](https://github.com/jlfwong/speedscope/pull/492)] (by @jlfwong)
|
||||
- Add link to async-profiler wiki page to README
|
||||
|
||||
## [1.21.0] - 2024-11-16
|
||||
|
||||
- Add support for Instruments 16 Time Profile Deep Copy [[#484](https://github.com/jlfwong/speedscope/pull/484)] (by @robert3005)
|
||||
- Fix bug where import after error continues failing [[#463](https://github.com/jlfwong/speedscope/pull/463)] (by @tom93)
|
||||
- Bundle the font [[#472](https://github.com/jlfwong/speedscope/pull/472)] (by @Krinkle)
|
||||
- Clarify specification of startValue in speedscope file format [[#464](https://github.com/jlfwong/speedscope/pull/464)] (by @tom93)
|
||||
|
||||
## [1.20.0] - 2024-01-12
|
||||
|
||||
- Partition based on samples instead of traceEvents when importing a sample-based chrome trace [[#460](https://github.com/jlfwong/speedscope/pull/460)] (by @zacharyfmarion)
|
||||
|
||||
## [1.19.0] - 2023-12-27
|
||||
|
||||
- Improve hermes profile frame keys to better group frames [[#459](https://github.com/jlfwong/speedscope/pull/459)] (by @zacharyfmarion)
|
||||
- Update README.md
|
||||
|
||||
## [1.18.0] - 2023-12-26
|
||||
|
||||
- Add hermes-specific support for the trace event format [[#458](https://github.com/jlfwong/speedscope/pull/458)] (by @zacharyfmarion)
|
||||
- Update README-ADMINS.md with npm login instructions [[#457](https://github.com/jlfwong/speedscope/pull/457)] (by @jlfwong)
|
||||
|
||||
## [1.17.0] - 2023-12-25
|
||||
|
||||
- Upgrade prettier, update prettier & react-hooks eslint plugins [[#456](https://github.com/jlfwong/speedscope/pull/456)] (by @jlfwong)
|
||||
- Upgrade typescript & eslint to latest, fix resulting errors [[#455](https://github.com/jlfwong/speedscope/pull/455)] (by @jlfwong)
|
||||
- Re-enable eslint prettier rule after being accidentally disabled for 3 years [[#454](https://github.com/jlfwong/speedscope/pull/454)] (by @jlfwong)
|
||||
- Support the chrome JSON trace format (allows viewing of hermes traces) [[#453](https://github.com/jlfwong/speedscope/pull/453)] (by @zacharyfmarion)
|
||||
- Fix bug in selectQueueToTakeFromNext for trace profiles [[#450](https://github.com/jlfwong/speedscope/pull/450)] (by @zacharyfmarion)
|
||||
- Add bounds checking for sampleTypeIndex [[#449](https://github.com/jlfwong/speedscope/pull/449)] (by @jlfwong)
|
||||
- Update README-zh_CN.md [[#442](https://github.com/jlfwong/speedscope/pull/442)] (by @byronhe)
|
||||
- Update publish-and-deploy to remove automated release creation [[#440](https://github.com/jlfwong/speedscope/pull/440)] (by @jlfwong)
|
||||
|
||||
## [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
|
||||
|
||||
- Replace fuzzy matching with exact substring matching for finding matching frames [[#407](https://github.com/jlfwong/speedscope/pull/407)]
|
||||
|
||||
## [1.14.0] - 2022-05-19
|
||||
|
||||
### Added
|
||||
|
||||
+14
-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,23 @@ 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
|
||||
In your default browser, ensure that you're logged into your npm account, otherwise you'll see a 404 page when you open the authenticate link during the npm publish.
|
||||
|
||||
Assuming everything went well in the previous two phases, publishing should just be
|
||||
a matter of running `npm publish`.
|
||||
Once ready to publish, run:
|
||||
|
||||
### Verifying the publish
|
||||
scripts/publish-and-deploy.sh
|
||||
|
||||
To verify that the publish was successful, run `npm install -g speedscope`.
|
||||
## Verifying the release
|
||||
|
||||
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/
|
||||
|
||||
+2
-2
@@ -12,7 +12,7 @@
|
||||
|
||||
# 使用
|
||||
|
||||
访问https://www.speedscope.app,上传文件或者拖拽到页面上。配置文件不会上传到任何地方——应用程序完全在浏览器中。
|
||||
访问 <https://www.speedscope.app> ,上传文件或者拖拽到页面上。配置文件不会上传到任何地方——应用程序完全在浏览器中。
|
||||
|
||||
## 命令行中使用
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
## 独立使用
|
||||
|
||||
如果你不想使用npm或者node下载,你也可以在这里下载独立的版本https://github.com/jlfwong/speedscope/releases.
|
||||
如果你不想使用npm或者node下载,你也可以在这里下载独立的版本 <https://github.com/jlfwong/speedscope/releases>.
|
||||
下载完一个版本的压缩文件之后,解压并在谷歌或者火狐浏览器中打开`index.html`文件即可。
|
||||
|
||||
## 支持的文件格式
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
English | [简体中文](./README-zh_CN.md)
|
||||
# 🔬speedscope
|
||||
|
||||
A fast, interactive web-based viewer for performance profiles. An alternative viewer for [FlameGraphs][1]. Will happily display multi-megabyte profiles without crashing your browser.
|
||||
A fast, interactive web-based viewer for performance profiles. Supports import from a variety of profiles in a variety of languages (JS, Ruby, Python, Go & more). Try it here: https://www.speedscope.app
|
||||
|
||||
Given raw profiling data, speedscope allows you to interactively explore the data to get insight into what's slow in your application, or allocating all the memory, or whatever data is represented in the profiling data.
|
||||
|
||||
@@ -10,6 +9,42 @@ Given raw profiling data, speedscope allows you to interactively explore the dat
|
||||
[0]: https://en.wikipedia.org/wiki/Profiling_(computer_programming)#Statistical_profilers
|
||||
[1]: https://github.com/brendangregg/FlameGraph
|
||||
|
||||
# Supported file formats
|
||||
|
||||
speedscope is designed to ingest profiles from a variety of different profilers for different programming languages & environments. Click the links below for documentation on how to import from a specific source.
|
||||
|
||||
- JavaScript
|
||||
- [Importing from Chrome](https://github.com/jlfwong/speedscope/wiki/Importing-from-Chrome)
|
||||
- [Importing from Firefox](https://github.com/jlfwong/speedscope/wiki/Importing-from-Firefox)
|
||||
- [Importing from Safari](https://github.com/jlfwong/speedscope/wiki/Importing-from-Safari)
|
||||
- [Importing from Node.js](https://github.com/jlfwong/speedscope/wiki/Importing-from-Node.js)
|
||||
- [Importing from Hermes (for React Native)](https://github.com/jlfwong/speedscope/wiki/Importing-from-Hermes)
|
||||
- Ruby
|
||||
- [Importing from stackprof](https://github.com/jlfwong/speedscope/wiki/Importing-from-stackprof-(ruby))
|
||||
- [Importing from rbspy](https://github.com/jlfwong/speedscope/wiki/Importing-from-rbspy-(ruby))
|
||||
- [Importing from ruby-prof](https://github.com/jlfwong/speedscope/wiki/Importing-from-ruby-prof)
|
||||
- Python
|
||||
- [Importing from py-spy](https://github.com/jlfwong/speedscope/wiki/Importing-from-py-spy-(python))
|
||||
- [pyspeedscope](https://github.com/windelbouwman/pyspeedscope)
|
||||
- [Importing from Austin](https://github.com/P403n1x87/austin-python#format-conversion)
|
||||
- [Importing from pyinstrument](https://github.com/jlfwong/speedscope/wiki/Importing-from-pyinstrument-(python))
|
||||
- PHP
|
||||
- [Importing from phpspy or sj-i/php-profiler](https://github.com/sj-i/php-profiler/pull/101)
|
||||
- Go
|
||||
- [Importing from pprof](https://github.com/jlfwong/speedscope/wiki/Importing-from-pprof-(go))
|
||||
- Rust
|
||||
- [flamescope](https://github.com/coolreader18/flamescope)
|
||||
- Java
|
||||
- [Importing from async‐profiler (Java)
|
||||
](https://github.com/jlfwong/speedscope/wiki/Importing-from-async%E2%80%90profiler-(Java))
|
||||
- Native code
|
||||
- [Importing from Instruments.app](https://github.com/jlfwong/speedscope/wiki/Importing-from-Instruments.app) (macOS)
|
||||
- [Importing from `perf`](https://github.com/jlfwong/speedscope/wiki/Importing-from-perf-(linux)) (linux)
|
||||
- [Importing from .NET Core](https://github.com/jlfwong/speedscope/wiki/Importing-from-.NET-Core)
|
||||
- [Importing from GHC (Haskell)](https://github.com/jlfwong/speedscope/wiki/Importing-from-Haskell)
|
||||
- [Importing from custom sources](https://github.com/jlfwong/speedscope/wiki/Importing-from-custom-sources)
|
||||
|
||||
Contributions to add support for additional formats are welcome! See issues with the ["import source" tag](https://github.com/jlfwong/speedscope/issues?q=is%3Aissue+is%3Aopen+label%3A%22import+source%22).
|
||||
# Usage
|
||||
|
||||
Visit https://www.speedscope.app, then either browse to find a profile file or drag-and-drop one onto the page. The profiles are not uploaded anywhere -- the application is totally in-browser.
|
||||
@@ -30,39 +65,6 @@ self-contained version from https://github.com/jlfwong/speedscope/releases.
|
||||
After you download the zip file from a release, simply unzip it and open the
|
||||
contained `index.html` in Chrome or Firefox.
|
||||
|
||||
## Supported file formats
|
||||
|
||||
speedscope is designed to ingest profiles from a variety of different profilers for different programming languages & environments. Click the links below for documentation on how to import from a specific source.
|
||||
|
||||
- JavaScript
|
||||
- [Importing from Chrome](https://github.com/jlfwong/speedscope/wiki/Importing-from-Chrome)
|
||||
- [Importing from Firefox](https://github.com/jlfwong/speedscope/wiki/Importing-from-Firefox)
|
||||
- [Importing from Safari](https://github.com/jlfwong/speedscope/wiki/Importing-from-Safari)
|
||||
- [Importing from Node.js](https://github.com/jlfwong/speedscope/wiki/Importing-from-Node.js)
|
||||
- Ruby
|
||||
- [Importing from stackprof](https://github.com/jlfwong/speedscope/wiki/Importing-from-stackprof-(ruby))
|
||||
- [Importing from rbspy](https://github.com/jlfwong/speedscope/wiki/Importing-from-rbspy-(ruby))
|
||||
- [Importing from ruby-prof](https://github.com/jlfwong/speedscope/wiki/Importing-from-ruby-prof)
|
||||
- Python
|
||||
- [Importing from py-spy](https://github.com/jlfwong/speedscope/wiki/Importing-from-py-spy-(python))
|
||||
- [pyspeedscope](https://github.com/windelbouwman/pyspeedscope)
|
||||
- [Importing from Austin](https://github.com/P403n1x87/austin-python#format-conversion)
|
||||
- [Importing from pyinstrument](https://github.com/jlfwong/speedscope/wiki/Importing-from-pyinstrument-(python))
|
||||
- PHP
|
||||
- [Importing from phpspy or sj-i/php-profiler](https://github.com/sj-i/php-profiler/pull/101)
|
||||
- Go
|
||||
- [Importing from pprof](https://github.com/jlfwong/speedscope/wiki/Importing-from-pprof-(go))
|
||||
- Rust
|
||||
- [flamescope](https://github.com/coolreader18/flamescope)
|
||||
- Native code
|
||||
- [Importing from Instruments.app](https://github.com/jlfwong/speedscope/wiki/Importing-from-Instruments.app) (macOS)
|
||||
- [Importing from `perf`](https://github.com/jlfwong/speedscope/wiki/Importing-from-perf-(linux)) (linux)
|
||||
- [Importing from .NET Core](https://github.com/jlfwong/speedscope/wiki/Importing-from-.NET-Core)
|
||||
- [Importing from GHC (Haskell)](https://github.com/jlfwong/speedscope/wiki/Importing-from-Haskell)
|
||||
- [Importing from custom sources](https://github.com/jlfwong/speedscope/wiki/Importing-from-custom-sources)
|
||||
|
||||
Contributions to add support for additional formats are welcome! See issues with the ["import source" tag](https://github.com/jlfwong/speedscope/issues?q=is%3Aissue+is%3Aopen+label%3A%22import+source%22).
|
||||
|
||||
## Importing via URL
|
||||
|
||||
To load a specific profile by URL, you can append a hash fragment like `#profileURL=[URL-encoded profile URL]&title=[URL-encoded custom title]`. Note that the server hosting the profile must have CORS configured to allow AJAX requests from speedscope.
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>speedscope</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet">
|
||||
<script>
|
||||
// https://github.com/evanw/webgl-recorder
|
||||
false && (function () {
|
||||
var getContext = HTMLCanvasElement.prototype.getContext;
|
||||
var requestAnimationFrame = window.requestAnimationFrame;
|
||||
var frameSincePageLoad = 0;
|
||||
|
||||
function countFrames() {
|
||||
frameSincePageLoad++;
|
||||
requestAnimationFrame(countFrames);
|
||||
}
|
||||
|
||||
window.requestAnimationFrame = function () {
|
||||
return requestAnimationFrame.apply(window, arguments);
|
||||
};
|
||||
|
||||
HTMLCanvasElement.prototype.getContext = function (type) {
|
||||
var canvas = this;
|
||||
var context = getContext.apply(canvas, arguments);
|
||||
|
||||
if (type === 'webgl' || type === 'experimental-webgl') {
|
||||
var oldWidth = canvas.width;
|
||||
var oldHeight = canvas.height;
|
||||
var oldFrameCount = frameSincePageLoad;
|
||||
var trace = [];
|
||||
var variables = {};
|
||||
var fakeContext = {
|
||||
trace: trace,
|
||||
compileTrace: compileTrace,
|
||||
downloadTrace: downloadTrace,
|
||||
};
|
||||
|
||||
trace.push(' gl.canvas.width = ' + oldWidth + ';');
|
||||
trace.push(' gl.canvas.height = ' + oldHeight + ';');
|
||||
|
||||
function compileTrace() {
|
||||
var text = 'function* render(gl) {\n';
|
||||
text += ' // Recorded using https://github.com/evanw/webgl-recorder\n';
|
||||
for (var key in variables) {
|
||||
text += ' var ' + key + 's = [];\n';
|
||||
}
|
||||
text += trace.join('\n');
|
||||
text += '\n}\n';
|
||||
return text;
|
||||
}
|
||||
|
||||
function downloadTrace() {
|
||||
var text = compileTrace();
|
||||
var link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(new Blob([text], { type: 'application/javascript' }));
|
||||
link.download = 'trace.js';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
|
||||
function getVariable(value) {
|
||||
if (value instanceof WebGLActiveInfo ||
|
||||
value instanceof WebGLBuffer ||
|
||||
value instanceof WebGLFramebuffer ||
|
||||
value instanceof WebGLProgram ||
|
||||
value instanceof WebGLRenderbuffer ||
|
||||
value instanceof WebGLShader ||
|
||||
value instanceof WebGLShaderPrecisionFormat ||
|
||||
value instanceof WebGLTexture ||
|
||||
value instanceof WebGLUniformLocation) {
|
||||
var name = value.constructor.name;
|
||||
var list = variables[name] || (variables[name] = []);
|
||||
var index = list.indexOf(value);
|
||||
|
||||
if (index === -1) {
|
||||
index = list.length;
|
||||
list.push(value);
|
||||
}
|
||||
|
||||
return name + 's[' + index + ']';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
console.timeStamp('start')
|
||||
var start = performance.now()
|
||||
for (var key in context) {
|
||||
var value = context[key];
|
||||
|
||||
if (typeof value === 'function') {
|
||||
fakeContext[key] = function (key, value) {
|
||||
return function () {
|
||||
trace.push(`// ${performance.now() - start}`)
|
||||
var result = value.apply(context, arguments);
|
||||
var args = [];
|
||||
|
||||
if (frameSincePageLoad !== oldFrameCount) {
|
||||
oldFrameCount = frameSincePageLoad;
|
||||
trace.push(' yield;');
|
||||
}
|
||||
|
||||
if (canvas.width !== oldWidth || canvas.height !== oldHeight) {
|
||||
oldWidth = canvas.width;
|
||||
oldHeight = canvas.height;
|
||||
trace.push(' gl.canvas.width = ' + oldWidth + ';');
|
||||
trace.push(' gl.canvas.height = ' + oldHeight + ';');
|
||||
}
|
||||
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
var arg = arguments[i];
|
||||
|
||||
if (typeof arg === 'number' || typeof arg === 'boolean' || typeof arg === 'string' || arg === null) {
|
||||
args.push(JSON.stringify(arg));
|
||||
}
|
||||
|
||||
else if (ArrayBuffer.isView(arg)) {
|
||||
args.push('new ' + arg.constructor.name + '([' + Array.prototype.slice.call(arg) + '])');
|
||||
}
|
||||
|
||||
else {
|
||||
var variable = getVariable(arg);
|
||||
if (variable !== null) {
|
||||
args.push(variable);
|
||||
}
|
||||
|
||||
else {
|
||||
console.log('unsupported value:', arg);
|
||||
args.push('null');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var text = 'gl.' + key + '(' + args.join(', ') + ');';
|
||||
var variable = getVariable(result);
|
||||
if (variable !== null) text = variable + ' = ' + text;
|
||||
trace.push(' ' + text);
|
||||
|
||||
return result;
|
||||
};
|
||||
}(key, value);
|
||||
}
|
||||
|
||||
else {
|
||||
fakeContext[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return fakeContext;
|
||||
}
|
||||
|
||||
return context;
|
||||
};
|
||||
|
||||
countFrames();
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="reset.css">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="../src/speedscope.tsx"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,7 @@
|
||||
@font-face{
|
||||
font-family: 'Source Code Pro';
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-stretch: normal;
|
||||
src: url('./source-code-pro/SourceCodePro-Regular.ttf.woff2') format('woff2');
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
Copyright 2010-2019 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Generated
+4511
-13039
File diff suppressed because it is too large
Load Diff
+13
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.14.0",
|
||||
"version": "1.21.2",
|
||||
"description": "",
|
||||
"repository": "jlfwong/speedscope",
|
||||
"main": "index.js",
|
||||
@@ -9,14 +9,14 @@
|
||||
},
|
||||
"scripts": {
|
||||
"deploy": "./scripts/deploy.sh",
|
||||
"prepack": "./scripts/build-release.sh",
|
||||
"prepack": "./scripts/prepack.sh --outdir \"$(pwd)/dist/release\" --protocol file",
|
||||
"prettier": "prettier --write 'src/**/*.ts' 'src/**/*.tsx'",
|
||||
"lint": "eslint 'src/**/*.ts' 'src/**/*.tsx'",
|
||||
"jest": "./scripts/test-setup.sh && jest --runInBand",
|
||||
"coverage": "npm run jest -- --coverage",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "./scripts/ci.sh",
|
||||
"serve": "parcel assets/index.html --open --no-autoinstall"
|
||||
"serve": "tsx scripts/dev-server.ts"
|
||||
},
|
||||
"files": [
|
||||
"bin/cli.js",
|
||||
@@ -34,27 +34,28 @@
|
||||
"@types/jszip": "3.1.4",
|
||||
"@types/node": "14.0.1",
|
||||
"@types/pako": "1.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "4.19.0",
|
||||
"@typescript-eslint/parser": "4.19.0",
|
||||
"@typescript-eslint/eslint-plugin": "6.16.0",
|
||||
"@typescript-eslint/parser": "6.16.0",
|
||||
"acorn": "7.2.0",
|
||||
"aphrodite": "2.1.0",
|
||||
"eslint": "6.0.0",
|
||||
"eslint-plugin-prettier": "2.6.0",
|
||||
"eslint-plugin-react-hooks": "4.0.2",
|
||||
"esbuild": "0.24.2",
|
||||
"eslint": "8.0.0",
|
||||
"eslint-plugin-prettier": "5.1.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"jest": "24.3.0",
|
||||
"jsverify": "0.8.3",
|
||||
"jszip": "3.1.5",
|
||||
"pako": "1.0.6",
|
||||
"parcel-bundler": "1.12.4",
|
||||
"preact": "10.4.1",
|
||||
"prettier": "2.0.4",
|
||||
"prettier": "3.1.1",
|
||||
"protobufjs": "6.8.8",
|
||||
"source-map": "0.6.1",
|
||||
"ts-jest": "24.3.0",
|
||||
"typescript": "4.2.3",
|
||||
"tsx": "4.19.2",
|
||||
"typescript": "5.3.3",
|
||||
"typescript-json-schema": "0.42.0",
|
||||
"uglify-es": "3.2.2",
|
||||
"uint8array-json-parser": "jlfwong/uint8array-json-parser#edce51ce"
|
||||
"uint8array-json-parser": "0.0.2"
|
||||
},
|
||||
"jest": {
|
||||
"transform": {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
Weight Self Weight Symbol Name
|
||||
96.08 Gc 100.0% - example_app (40414)
|
||||
96.08 Gc 100.0% - start
|
||||
96.08 Gc 100.0% - main
|
||||
96.08 Gc 100.0% - std::rt::lang_start::hdba6f1ebfd1bdcf8
|
||||
96.08 Gc 100.0% - std::rt::lang_start_internal::hc453db0ee48af82e
|
||||
96.08 Gc 100.0% - std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c
|
||||
96.08 Gc 100.0% - std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc
|
||||
96.08 Gc 100.0% - core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8
|
||||
96.08 Gc 100.0% - example_app::main::hddab13ae8d8b6a6e
|
||||
47.82 Gc 49.7% - example_app::example_a::h622d6879b734496d
|
||||
46.92 Gc 48.8% 404.75 Mc std::time::Instant::elapsed::h2e3793148fc23529
|
||||
45.92 Gc 47.7% 45.92 Gc mach_absolute_time
|
||||
600.78 Mc 0.6% 600.78 Mc std::time::Instant::elapsed::h2e3793148fc23529
|
||||
1.00 Mc 0.0% 1.00 Mc DYLD-STUB$$mach_absolute_time
|
||||
634.35 Mc 0.6% 634.35 Mc core::time::Duration::as_millis::hae6ad1b9cf7bb5ec
|
||||
181.50 Mc 0.1% 181.50 Mc example_app::example_a::h622d6879b734496d
|
||||
84.45 Mc 0.0% - example_app::example_b::h71b31fcd89b9ffd2
|
||||
81.45 Mc 0.0% - std::time::Instant::elapsed::h2e3793148fc23529
|
||||
80.45 Mc 0.0% 80.45 Mc mach_absolute_time
|
||||
1.00 Mc 0.0% 1.00 Mc std::time::Instant::elapsed::h2e3793148fc23529
|
||||
1.00 Mc 0.0% - example_app::example_c::h631759c10d7dee93
|
||||
1.00 Mc 0.0% - alloc::vec::Vec$LT$T$C$A$GT$::push::ha3426502ffc42c8b
|
||||
1.00 Mc 0.0% - alloc::raw_vec::RawVec$LT$T$C$A$GT$::reserve_for_push::he4a29b8274e35dbb
|
||||
1.00 Mc 0.0% - alloc::raw_vec::RawVec$LT$T$C$A$GT$::grow_amortized::h78db9ba423623c58
|
||||
1.00 Mc 0.0% - alloc::raw_vec::finish_grow::h876f5af1c66d74c8
|
||||
1.00 Mc 0.0% - _$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$::allocate::hcc733a40a34fbc94
|
||||
1.00 Mc 0.0% - alloc::alloc::Global::alloc_impl::hc55feba7d6266dfa
|
||||
1.00 Mc 0.0% - alloc::alloc::alloc::hfac63f3d6850b759
|
||||
1.00 Mc 0.0% - _malloc_zone_malloc
|
||||
1.00 Mc 0.0% - nanov2_malloc
|
||||
1.00 Mc 0.0% - nanov2_allocate
|
||||
1.00 Mc 0.0% - nanov2_allocate
|
||||
1.00 Mc 0.0% 1.00 Mc nanov2_find_block_and_allocate
|
||||
1.00 Mc 0.0% 1.00 Mc example_app::example_b::h71b31fcd89b9ffd2
|
||||
1.00 Mc 0.0% 1.00 Mc core::time::Duration::as_millis::hae6ad1b9cf7bb5ec
|
||||
47.45 Gc 49.3% 415.12 Mc std::time::Instant::elapsed::h2e3793148fc23529
|
||||
46.39 Gc 48.2% 46.39 Gc mach_absolute_time
|
||||
649.70 Mc 0.6% 649.70 Mc std::time::Instant::elapsed::h2e3793148fc23529
|
||||
614.22 Mc 0.6% 614.22 Mc core::time::Duration::as_millis::hae6ad1b9cf7bb5ec
|
||||
190.55 Mc 0.1% 190.55 Mc example_app::main::hddab13ae8d8b6a6e
|
||||
1.34 Kc 0.0% - std::io::stdio::_print::hdecfefdeb43586ed
|
||||
1.34 Kc 0.0% - _$LT$$RF$std..io..stdio..Stdout$u20$as$u20$std..io..Write$GT$::write_fmt::h2cb06dcd2b172844
|
||||
1.34 Kc 0.0% - core::fmt::write::hed96bcfc6342aee5
|
||||
532 cycles 0.0% - _$LT$std..io..Write..write_fmt..Adapter$LT$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::hbe33ec23de24ce2f
|
||||
532 cycles 0.0% 532 cycles _$LT$std..io..stdio..StdoutLock$u20$as$u20$std..io..Write$GT$::write_all::h22667d0a03b2151b
|
||||
@@ -0,0 +1,95 @@
|
||||
Weight Self Weight Symbol Names
|
||||
4.93 s 100.0% 0 s start
|
||||
4.93 s 99.9% 0 s main
|
||||
2.45 s 0.0% 846.00 ms delta()
|
||||
797.00 ms 0.0% 786.00 ms alpha()
|
||||
9.00 ms 0.0% 0 s leakMemory()
|
||||
8.00 ms 0.0% 1.00 ms szone_malloc_should_clear
|
||||
6.00 ms 0.0% 4.00 ms small_malloc_should_clear
|
||||
2.00 ms 0.0% 2.00 ms small_malloc_from_free_list
|
||||
1.00 ms 0.0% 1.00 ms small_malloc_from_free_list
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
2.00 ms 0.0% 2.00 ms _malloc_zone_malloc
|
||||
795.00 ms 0.0% 778.00 ms beta()
|
||||
14.00 ms 0.0% 1.00 ms leakMemory()
|
||||
11.00 ms 0.0% 2.00 ms szone_malloc_should_clear
|
||||
9.00 ms 0.0% 3.00 ms small_malloc_should_clear
|
||||
5.00 ms 0.0% 5.00 ms small_malloc_from_free_list
|
||||
1.00 ms 0.0% 1.00 ms rack_get_thread_index
|
||||
1.00 ms 0.0% 1.00 ms nanov2_malloc_type
|
||||
1.00 ms 0.0% 1.00 ms DYLD-STUB$$malloc
|
||||
2.00 ms 0.0% 2.00 ms nanov2_malloc_type
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
10.00 ms 0.0% 0 s leakMemory()
|
||||
7.00 ms 0.0% 3.00 ms szone_malloc_should_clear
|
||||
4.00 ms 0.0% 3.00 ms small_malloc_should_clear
|
||||
1.00 ms 0.0% 0 s mvm_allocate_pages_plat
|
||||
1.00 ms 0.0% 1.00 ms _kernelrpc_mach_vm_map_trap
|
||||
2.00 ms 0.0% 2.00 ms small_malloc_should_clear
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
3.00 ms 0.0% 3.00 ms _malloc_zone_malloc
|
||||
838.00 ms 0.0% 827.00 ms gamma()
|
||||
9.00 ms 0.0% 1.00 ms leakMemory()
|
||||
5.00 ms 0.0% 0 s szone_malloc_should_clear
|
||||
4.00 ms 0.0% 1.00 ms small_malloc_should_clear
|
||||
3.00 ms 0.0% 3.00 ms small_malloc_from_free_list
|
||||
1.00 ms 0.0% 1.00 ms rack_get_thread_index
|
||||
1.00 ms 0.0% 1.00 ms small_malloc_should_clear
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
1.00 ms 0.0% 1.00 ms nanov2_malloc_type
|
||||
2.00 ms 0.0% 2.00 ms _malloc_zone_malloc
|
||||
834.00 ms 0.0% 824.00 ms beta()
|
||||
9.00 ms 0.0% 0 s leakMemory()
|
||||
7.00 ms 0.0% 0 s szone_malloc_should_clear
|
||||
6.00 ms 0.0% 1.00 ms small_malloc_should_clear
|
||||
4.00 ms 0.0% 4.00 ms small_malloc_from_free_list
|
||||
1.00 ms 0.0% 1.00 ms rack_get_thread_index
|
||||
1.00 ms 0.0% 1.00 ms rack_get_thread_index
|
||||
1.00 ms 0.0% 1.00 ms nanov2_malloc_type
|
||||
1.00 ms 0.0% 1.00 ms small_malloc_should_clear
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
803.00 ms 0.0% 788.00 ms alpha()
|
||||
14.00 ms 0.0% 0 s leakMemory()
|
||||
11.00 ms 0.0% 1.00 ms szone_malloc_should_clear
|
||||
10.00 ms 0.0% 3.00 ms small_malloc_should_clear
|
||||
5.00 ms 0.0% 5.00 ms small_malloc_from_free_list
|
||||
2.00 ms 0.0% 2.00 ms rack_get_thread_index
|
||||
1.00 ms 0.0% 1.00 ms nanov2_malloc_type
|
||||
1.00 ms 0.0% 1.00 ms small_malloc_should_clear
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
1.00 ms 0.0% 1.00 ms _malloc_zone_malloc
|
||||
4.00 ms 0.1% 0 s dyld4::start(dyld4::KernelArgs*, void*, void*)::$_0::operator()() const
|
||||
4.00 ms 0.1% 0 s dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*)
|
||||
3.00 ms 0.0% 0 s dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&)
|
||||
3.00 ms 0.0% 0 s mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const
|
||||
3.00 ms 0.0% 0 s mach_o::Header::forEachLoadCommand(void (load_command const*, bool&) block_pointer) const
|
||||
3.00 ms 0.0% 0 s invocation function for block in mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const
|
||||
3.00 ms 0.0% 0 s invocation function for block in dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&)
|
||||
3.00 ms 0.0% 0 s dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&)
|
||||
3.00 ms 0.0% 0 s dyld4::Loader::forEachPath(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer)
|
||||
3.00 ms 0.0% 0 s dyld4::ProcessConfig::PathOverrides::forEachPathVariant(char const*, dyld3::Platform, bool, bool, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer) const
|
||||
3.00 ms 0.0% 0 s dyld4::Loader::forEachResolvedAtPathVar(dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, dyld4::ProcessConfig::PathOverrides::Type, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer)
|
||||
3.00 ms 0.0% 0 s invocation function for block in dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&)
|
||||
3.00 ms 0.0% 0 s dyld4::Loader::makeDyldCacheLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, unsigned int, mach_o::Layout const*)
|
||||
3.00 ms 0.0% 0 s dyld4::RuntimeState::findPrebuiltLoader(char const*) const
|
||||
3.00 ms 0.0% 0 s dyld4::PrebuiltLoader::isValid(dyld4::RuntimeState const&) const
|
||||
3.00 ms 0.0% 0 s dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const
|
||||
3.00 ms 0.0% 0 s dyld4::ProcessConfig::PathOverrides::forEachPathVariant(char const*, dyld3::Platform, bool, bool, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer) const
|
||||
3.00 ms 0.0% 0 s invocation function for block in dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const
|
||||
3.00 ms 0.0% 0 s dyld4::SyscallDelegate::fileExists(char const*, dyld4::FileID*, int*) const
|
||||
3.00 ms 0.0% 0 s dyld3::stat(char const*, stat*)
|
||||
3.00 ms 0.0% 3.00 ms stat
|
||||
1.00 ms 0.0% 0 s dyld4::APIs::runAllInitializersForMain()
|
||||
1.00 ms 0.0% 0 s dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const
|
||||
1.00 ms 0.0% 0 s dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::operator()() const
|
||||
1.00 ms 0.0% 0 s dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const
|
||||
1.00 ms 0.0% 0 s dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const
|
||||
1.00 ms 0.0% 0 s dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const
|
||||
1.00 ms 0.0% 0 s dyld4::PrebuiltLoader::runInitializers(dyld4::RuntimeState&) const
|
||||
1.00 ms 0.0% 0 s dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const
|
||||
1.00 ms 0.0% 0 s dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const
|
||||
1.00 ms 0.0% 0 s dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const
|
||||
1.00 ms 0.0% 0 s dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const
|
||||
1.00 ms 0.0% 0 s invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const
|
||||
1.00 ms 0.0% 0 s invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const
|
||||
1.00 ms 0.0% 1.00 ms _GLOBAL__sub_I_stdlib_typed_new.cpp
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
{"version":"0.0.1","$schema":"https://www.speedscope.app/file-format-schema.json","shared":{"frames":[{"name":"a"},{"name":"b"},{"name":"c"},{"name":"d"}]},"profiles":[{"type":"evented","name":"simple.txt","unit":"none","startValue":0,"endValue":14,"events":[{"type":"O","frame":0,"at":0},{"type":"O","frame":1,"at":0},{"type":"O","frame":2,"at":0},{"type":"C","frame":2,"at":2},{"type":"O","frame":3,"at":2},{"type":"C","frame":3,"at":6},{"type":"O","frame":2,"at":6},{"type":"C","frame":2,"at":9},{"type":"C","frame":1,"at":14},{"type":"C","frame":0,"at":14}]}]}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,156 @@
|
||||
[
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"B",
|
||||
"name":"[root]",
|
||||
"ts":0,
|
||||
"args":{
|
||||
"name":"[root]",
|
||||
"category":"root",
|
||||
"url":null,
|
||||
"line":null,
|
||||
"column":null,
|
||||
"params":null,
|
||||
"allocatedCategory":"root",
|
||||
"allocatedName":"[root]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"B",
|
||||
"name":"beta",
|
||||
"ts":1,
|
||||
"args":{
|
||||
"line":54,
|
||||
"column":12,
|
||||
"funcLine":"1",
|
||||
"funcColumn":"1",
|
||||
"name":"beta",
|
||||
"category":"JavaScript",
|
||||
"parent":1,
|
||||
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params":null,
|
||||
"allocatedCategory":"JavaScript",
|
||||
"allocatedName":"beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"E",
|
||||
"name":"beta",
|
||||
"ts":2,
|
||||
"args":{
|
||||
"line":54,
|
||||
"column":12,
|
||||
"funcLine":"1",
|
||||
"funcColumn":"1",
|
||||
"name":"beta",
|
||||
"category":"JavaScript",
|
||||
"parent":1,
|
||||
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params":null,
|
||||
"allocatedCategory":"JavaScript",
|
||||
"allocatedName":"beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"B",
|
||||
"name":"gamma",
|
||||
"ts":4,
|
||||
"args":{
|
||||
"line":54,
|
||||
"column":12,
|
||||
"funcLine":"1",
|
||||
"funcColumn":"1",
|
||||
"name":"beta",
|
||||
"category":"blah",
|
||||
"parent":1,
|
||||
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params":null,
|
||||
"allocatedCategory":"JavaScript",
|
||||
"allocatedName":"beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"E",
|
||||
"name":"gamma",
|
||||
"ts":13,
|
||||
"args":{
|
||||
"line":54,
|
||||
"column":12,
|
||||
"funcLine":"1",
|
||||
"funcColumn":"1",
|
||||
"name":"beta",
|
||||
"category":"blah",
|
||||
"parent":1,
|
||||
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params":null,
|
||||
"allocatedCategory":"JavaScript",
|
||||
"allocatedName":"beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"B",
|
||||
"name":"beta",
|
||||
"ts":4,
|
||||
"args":{
|
||||
"line":54,
|
||||
"column":12,
|
||||
"funcLine":"1",
|
||||
"funcColumn":"1",
|
||||
"name":"beta",
|
||||
"category":"blah",
|
||||
"parent":1,
|
||||
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params":null,
|
||||
"allocatedCategory":"JavaScript",
|
||||
"allocatedName":"beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"E",
|
||||
"name":"beta",
|
||||
"ts":10,
|
||||
"args":{
|
||||
"line":54,
|
||||
"column":12,
|
||||
"funcLine":"1",
|
||||
"funcColumn":"1",
|
||||
"name":"beta",
|
||||
"category":"blah",
|
||||
"parent":1,
|
||||
"url":"/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params":null,
|
||||
"allocatedCategory":"JavaScript",
|
||||
"allocatedName":"beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid":0,
|
||||
"tid":0,
|
||||
"ph":"E",
|
||||
"name":"[root]",
|
||||
"ts":14,
|
||||
"args":{
|
||||
"name":"[root]",
|
||||
"category":"root",
|
||||
"url":null,
|
||||
"line":null,
|
||||
"column":null,
|
||||
"params":null,
|
||||
"allocatedCategory":"root",
|
||||
"allocatedName":"[root]"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"traceEvents": [
|
||||
{
|
||||
"name": "process_name",
|
||||
"ph": "M",
|
||||
"cat": "__metadata",
|
||||
"pid": 7512,
|
||||
"ts": "11550183666",
|
||||
"tid": "-1",
|
||||
"args": {
|
||||
"name": "hermes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "thread_name",
|
||||
"ph": "M",
|
||||
"cat": "__metadata",
|
||||
"pid": 7512,
|
||||
"ts": "11550183666",
|
||||
"tid": "1",
|
||||
"args": {
|
||||
"name": "mqt_js"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mqt_js",
|
||||
"cat": "mqt_js",
|
||||
"ph": "X",
|
||||
"dur": 0,
|
||||
"pid": 7512,
|
||||
"ts": "11550183666",
|
||||
"tid": "1",
|
||||
"args": {}
|
||||
},
|
||||
{
|
||||
"name": "mqt_js",
|
||||
"cat": "mqt_js",
|
||||
"ph": "X",
|
||||
"dur": 0,
|
||||
"pid": 7512,
|
||||
"ts": "11550183666",
|
||||
"tid": "2",
|
||||
"args": {}
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552125241",
|
||||
"pid": 7512,
|
||||
"tid": "1",
|
||||
"weight": "1",
|
||||
"sf": 1
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552125241",
|
||||
"pid": 7512,
|
||||
"tid": "2",
|
||||
"weight": "1",
|
||||
"sf": 4
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552146011",
|
||||
"pid": 7512,
|
||||
"tid": "1",
|
||||
"weight": "1",
|
||||
"sf": 2
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552146011",
|
||||
"pid": 7512,
|
||||
"tid": "2",
|
||||
"weight": "1",
|
||||
"sf": 5
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552159337",
|
||||
"pid": 7512,
|
||||
"tid": "1",
|
||||
"weight": "1",
|
||||
"sf": 3
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552159337",
|
||||
"pid": 7512,
|
||||
"tid": "2",
|
||||
"weight": "1",
|
||||
"sf": 6
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552169337",
|
||||
"pid": 7512,
|
||||
"tid": "2",
|
||||
"weight": "1",
|
||||
"sf": 4
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552179337",
|
||||
"pid": 7512,
|
||||
"tid": "2",
|
||||
"weight": "1",
|
||||
"sf": 4
|
||||
}
|
||||
],
|
||||
"stackFrames": {
|
||||
"1": {
|
||||
"name": "[root]",
|
||||
"category": "root"
|
||||
},
|
||||
"2": {
|
||||
"name": "function1",
|
||||
"category": "JavaScript",
|
||||
"parent": 1
|
||||
},
|
||||
"3": {
|
||||
"name": "[GC Young Gen]",
|
||||
"category": "Metadata",
|
||||
"parent": 1
|
||||
},
|
||||
"4": {
|
||||
"name": "[root thread 2]",
|
||||
"category": "root"
|
||||
},
|
||||
"5": {
|
||||
"name": "function3",
|
||||
"category": "JavaScript",
|
||||
"parent": 4
|
||||
},
|
||||
"6": {
|
||||
"name": "function4",
|
||||
"category": "Metadata",
|
||||
"parent": 4
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
[
|
||||
{
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
"ph": "B",
|
||||
"name": "[root]",
|
||||
"ts": 0,
|
||||
"args": {
|
||||
"name": "[root]",
|
||||
"category": "root",
|
||||
"url": null,
|
||||
"line": null,
|
||||
"column": null,
|
||||
"params": null,
|
||||
"allocatedCategory": "root",
|
||||
"allocatedName": "[root]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
"ph": "B",
|
||||
"name": "beta",
|
||||
"ts": 1,
|
||||
"args": {
|
||||
"line": 54,
|
||||
"column": 12,
|
||||
"funcLine": "1",
|
||||
"funcColumn": "1",
|
||||
"name": "beta",
|
||||
"category": "JavaScript",
|
||||
"parent": 1,
|
||||
"url": "/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params": null,
|
||||
"allocatedCategory": "JavaScript",
|
||||
"allocatedName": "beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
"ph": "E",
|
||||
"name": "beta",
|
||||
"ts": 13,
|
||||
"args": {
|
||||
"line": 54,
|
||||
"column": 12,
|
||||
"funcLine": "1",
|
||||
"funcColumn": "1",
|
||||
"name": "beta",
|
||||
"category": "JavaScript",
|
||||
"parent": 1,
|
||||
"url": "/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"params": null,
|
||||
"allocatedCategory": "JavaScript",
|
||||
"allocatedName": "beta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pid": 0,
|
||||
"tid": 0,
|
||||
"ph": "E",
|
||||
"name": "[root]",
|
||||
"ts": 14,
|
||||
"args": {
|
||||
"name": "[root]",
|
||||
"category": "root",
|
||||
"url": null,
|
||||
"line": null,
|
||||
"column": null,
|
||||
"params": null,
|
||||
"allocatedCategory": "root",
|
||||
"allocatedName": "[root]"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"traceEvents": [
|
||||
{
|
||||
"name": "process_name",
|
||||
"ph": "M",
|
||||
"cat": "__metadata",
|
||||
"pid": 7512,
|
||||
"ts": "11550183666",
|
||||
"tid": "-1",
|
||||
"args": {
|
||||
"name": "hermes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "thread_name",
|
||||
"ph": "M",
|
||||
"cat": "__metadata",
|
||||
"pid": 7512,
|
||||
"ts": "11550183666",
|
||||
"tid": "7695",
|
||||
"args": {
|
||||
"name": "mqt_js"
|
||||
}
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552125241",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 1
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552129681",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 1
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552146011",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 2
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552159337",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 4
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552169942",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 1
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552179951",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 5
|
||||
},
|
||||
{
|
||||
"cpu": "-1",
|
||||
"name": "",
|
||||
"ts": "11552189951",
|
||||
"pid": 7512,
|
||||
"tid": "7695",
|
||||
"weight": "1",
|
||||
"sf": 5
|
||||
}
|
||||
],
|
||||
"stackFrames": {
|
||||
"1": {
|
||||
"name": "[root]",
|
||||
"category": "root"
|
||||
},
|
||||
"2": {
|
||||
"name": "function1(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:1:1)",
|
||||
"category": "JavaScript",
|
||||
"parent": 1
|
||||
},
|
||||
"3": {
|
||||
"name": "function2(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:418874:4)",
|
||||
"category": "JavaScript",
|
||||
"parent": 1
|
||||
},
|
||||
"4": {
|
||||
"name": "function3(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:17:3)",
|
||||
"category": "JavaScript",
|
||||
"parent": 3
|
||||
},
|
||||
"5": {
|
||||
"name": "[GC Young Gen]",
|
||||
"category": "Metadata",
|
||||
"parent": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
[
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "anonymous", "ts": 0},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "anonymous", "ts": 1, "args": { "parent": 1 }},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "function1", "ts": 1, "args": { "parent": 2 }},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "anonymous", "ts": 1, "args": { "parent": 3 }},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "anonymous", "ts": 3, "args": { "parent": 3 }},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "function1", "ts": 3, "args": { "parent": 2 }},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "anonymous", "ts": 3, "args": { "parent": 1 }},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "anonymous", "ts": 3, "args": { "parent": 1 }},
|
||||
{"pid": 0, "tid": 0, "ph": "B", "name": "anonymous", "ts": 3, "args": { "parent": 8 }},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "anonymous", "ts": 5, "args": { "parent": 8 }},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "anonymous", "ts": 5, "args": { "parent": 1 }},
|
||||
{"pid": 0, "tid": 0, "ph": "E", "name": "anonymous", "ts": 5}
|
||||
]
|
||||
@@ -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)
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
OUTDIR=`pwd`/dist/release
|
||||
|
||||
# Typecheck
|
||||
node_modules/.bin/tsc --noEmit
|
||||
|
||||
# Run unit tests
|
||||
npm run jest
|
||||
|
||||
# Clean out the release directory
|
||||
rm -rf "$OUTDIR"
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
# Place info about the current commit into the build dir to easily identify releases
|
||||
npm ls -depth -1 | head -n 1 | cut -d' ' -f 1 > "$OUTDIR"/release.txt
|
||||
date >> "$OUTDIR"/release.txt
|
||||
git rev-parse HEAD >> "$OUTDIR"/release.txt
|
||||
|
||||
# Place a json schema for the file format into the build directory too
|
||||
node scripts/generate-file-format-schema-json.js > "$OUTDIR"/file-format-schema.json
|
||||
|
||||
# Build the compiled assets
|
||||
node_modules/.bin/parcel build assets/index.html --no-cache --out-dir "$OUTDIR" --public-url "./" --detailed-report
|
||||
@@ -0,0 +1,56 @@
|
||||
import * as esbuild from 'esbuild'
|
||||
import {buildOptions, generateIndexHtml} from './esbuild-shared'
|
||||
|
||||
function parseArgs() {
|
||||
const args = process.argv.slice(2)
|
||||
const result: {outdir?: string; protocol?: 'http' | 'file'} = {}
|
||||
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
switch (args[i]) {
|
||||
case '--outdir':
|
||||
result.outdir = args[i + 1]
|
||||
break
|
||||
case '--protocol':
|
||||
result.protocol = args[i + 1] as 'http' | 'file'
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const {outdir, protocol: servingProtocol} = parseArgs()
|
||||
|
||||
if (!outdir || !servingProtocol) {
|
||||
console.error('Usage: build-release.ts --outdir <outdir> --protocol <serving_protocol>')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
if (servingProtocol !== 'http' && servingProtocol !== 'file') {
|
||||
console.error('serving_protocol must be either "http" or "file"')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let buildResult = await esbuild.build({
|
||||
...buildOptions,
|
||||
minify: true,
|
||||
metafile: true,
|
||||
...(servingProtocol === 'file'
|
||||
? {
|
||||
format: 'iife',
|
||||
splitting: false,
|
||||
}
|
||||
: {}),
|
||||
outdir,
|
||||
})
|
||||
|
||||
generateIndexHtml({
|
||||
buildResult,
|
||||
outdir,
|
||||
servingProtocol,
|
||||
})
|
||||
|
||||
console.log(`Successfully built to ${outdir}`)
|
||||
}
|
||||
|
||||
main()
|
||||
+6
-8
@@ -7,12 +7,10 @@
|
||||
set -euxo pipefail
|
||||
|
||||
SRCDIR=`pwd`
|
||||
OUTDIR=`mktemp -d -t speedscope-unpacked`
|
||||
OUTDIR=`pwd`/dist/http-release
|
||||
|
||||
# Untar the package
|
||||
pushd "$OUTDIR"
|
||||
PACKEDNAME=`npm pack speedscope | tail -n1`
|
||||
tar -xvvf "$PACKEDNAME"
|
||||
# Build the release with http protocol
|
||||
./scripts/prepack.sh --outdir "$OUTDIR" --protocol http
|
||||
|
||||
# Create a shallow clone of the repository
|
||||
TMPDIR=`mktemp -d -t speedscope-deploy`
|
||||
@@ -22,7 +20,7 @@ git clone --depth 1 git@github.com:jlfwong/speedscope.git -b gh-pages
|
||||
# Copy the build artifacts into the shallow clone
|
||||
pushd speedscope
|
||||
rm -rf *
|
||||
cp -R "$OUTDIR"/package/dist/release/** .
|
||||
cp -R "$OUTDIR"/* .
|
||||
|
||||
# Set the CNAME record
|
||||
echo www.speedscope.app > CNAME
|
||||
@@ -37,7 +35,7 @@ function ctrl_c() {
|
||||
if [[ $REPLY =~ ^yes$ ]]
|
||||
then
|
||||
git add --all
|
||||
git commit -m "Deploy $PACKEDNAME"
|
||||
git commit -m "Deploy $(date +%Y-%m-%d)"
|
||||
git push origin HEAD:gh-pages
|
||||
rm -rf "$TMPDIR"
|
||||
exit 0
|
||||
@@ -58,5 +56,5 @@ echo "Build complete. Starting server on http://localhost:4444/"
|
||||
echo "Hit Ctrl+C to complete or cancel the release"
|
||||
echo
|
||||
echo
|
||||
python -m SimpleHTTPServer 4444 .
|
||||
python3 -m http.server 4444
|
||||
set +x
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import * as esbuild from 'esbuild'
|
||||
import {buildOptions, generateIndexHtml} from './esbuild-shared'
|
||||
|
||||
async function main() {
|
||||
const outdir = 'dist'
|
||||
let ctx = await esbuild.context({
|
||||
...buildOptions,
|
||||
outdir,
|
||||
write: false,
|
||||
metafile: true,
|
||||
plugins: [
|
||||
{
|
||||
name: 'speedscope-dev-server',
|
||||
setup(build) {
|
||||
build.onEnd(buildResult => {
|
||||
generateIndexHtml({
|
||||
buildResult,
|
||||
outdir,
|
||||
servingProtocol: 'http',
|
||||
})
|
||||
})
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
await ctx.rebuild()
|
||||
|
||||
let {host, port} = await ctx.serve({
|
||||
servedir: outdir,
|
||||
})
|
||||
|
||||
console.log(`Server is running at http://${host}:${port}`)
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -0,0 +1,112 @@
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import * as esbuild from 'esbuild'
|
||||
|
||||
const entryPoint = 'src/speedscope.tsx'
|
||||
|
||||
export const buildOptions: esbuild.BuildOptions = {
|
||||
entryPoints: [
|
||||
entryPoint,
|
||||
|
||||
// This is a kind of silly way to ensure that all of these files end up being
|
||||
// discovered by esbuild and copied into the output directory
|
||||
'assets/favicon-16x16.png',
|
||||
'assets/favicon-32x32.png',
|
||||
'assets/favicon.ico',
|
||||
],
|
||||
entryNames: '[name]-[hash]',
|
||||
chunkNames: '[name]-[hash]',
|
||||
assetNames: '[name]-[hash]',
|
||||
sourcemap: true,
|
||||
bundle: true,
|
||||
format: 'esm',
|
||||
splitting: true,
|
||||
loader: {
|
||||
'.txt': 'file',
|
||||
'.woff2': 'file',
|
||||
'.png': 'file',
|
||||
'.ico': 'file',
|
||||
},
|
||||
}
|
||||
|
||||
interface GenerateIndexHtmlOptions {
|
||||
buildResult: esbuild.BuildResult
|
||||
outdir: string
|
||||
servingProtocol: 'file' | 'http'
|
||||
}
|
||||
|
||||
export const generateIndexHtml = ({
|
||||
buildResult,
|
||||
outdir,
|
||||
servingProtocol,
|
||||
}: GenerateIndexHtmlOptions) => {
|
||||
const outputs = buildResult.metafile!.outputs
|
||||
|
||||
function getOutput(entryPoint: string): [string, esbuild.Metafile['outputs'][string]] {
|
||||
const key = Object.keys(outputs).find(key => outputs[key].entryPoint === entryPoint)!
|
||||
return [key, outputs[key]]
|
||||
}
|
||||
|
||||
function getHashedFilePath(name: string) {
|
||||
return path.basename(getOutput(name)[1].imports.find(i => i.kind === 'file-loader')!.path)
|
||||
}
|
||||
|
||||
const [mainChunkPath, mainChunk] = getOutput(entryPoint)
|
||||
const mainChunkName = path.basename(mainChunkPath)
|
||||
|
||||
const mainChunkCssPath = mainChunk.cssBundle!
|
||||
const cssChunk = outputs[mainChunkCssPath]
|
||||
|
||||
const fontPath = cssChunk.imports.find(i => i.path.endsWith('.woff2'))!.path
|
||||
const fontName = path.basename(fontPath)
|
||||
|
||||
const syncDependencyNames = mainChunk.imports
|
||||
.filter(i => i.kind === 'import-statement')
|
||||
.map(i => path.basename(i.path))
|
||||
const asyncDependencyNames = mainChunk.imports
|
||||
.filter(i => i.kind === 'dynamic-import')
|
||||
.map(i => path.basename(i.path))
|
||||
|
||||
// If we're serving from a file protocol, we can't use module
|
||||
// scripts
|
||||
const scriptType = servingProtocol === 'file' ? '' : ' type="module"'
|
||||
|
||||
const favicon16x16Path = getHashedFilePath('assets/favicon-16x16.png')
|
||||
const favicon32x32Path = getHashedFilePath('assets/favicon-32x32.png')
|
||||
const faviconIcoPath = getHashedFilePath('assets/favicon.ico')
|
||||
|
||||
const html = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>speedscope</title>
|
||||
<link rel="stylesheet" href="${path.basename(mainChunk.cssBundle!)}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="${favicon32x32Path}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="${favicon16x16Path}">
|
||||
<link rel="icon" type="image/x-icon" href="${faviconIcoPath}">
|
||||
</head>
|
||||
<body>
|
||||
<script src="${mainChunkName}"${scriptType}></script>
|
||||
${syncDependencyNames.map(dep => `<script src="${dep}"${scriptType}></script>`).join('\n ')}
|
||||
${asyncDependencyNames
|
||||
.map(
|
||||
dep =>
|
||||
`<script src="${dep}"${scriptType}${
|
||||
servingProtocol === 'file' ? '' : ' async'
|
||||
}></script>`,
|
||||
)
|
||||
.join('\n ')}
|
||||
${
|
||||
/* Preload is blocked by CORS, so we can't use it with file:/// URLs */
|
||||
servingProtocol === 'file'
|
||||
? ''
|
||||
: `<link rel="preload" href="${fontName}" as="font" type="font/woff2" crossorigin>`
|
||||
}
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
fs.writeFileSync(`${outdir}/index.html`, html)
|
||||
}
|
||||
Executable
+53
@@ -0,0 +1,53 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--outdir)
|
||||
OUTDIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--protocol)
|
||||
PROTOCOL="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "Unknown argument: $1"
|
||||
echo "Usage: $0 --outdir <output_directory> --protocol <serving_protocol>"
|
||||
echo "serving_protocol must be either 'http' or 'file'"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Validate required arguments
|
||||
if [ -z "${OUTDIR:-}" ] || [ -z "${PROTOCOL:-}" ]; then
|
||||
echo "Usage: $0 --outdir <output_directory> --protocol <serving_protocol>"
|
||||
echo "serving_protocol must be either 'http' or 'file'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$PROTOCOL" != "http" ] && [ "$PROTOCOL" != "file" ]; then
|
||||
echo "Error: serving_protocol must be either 'http' or 'file'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean out the release directory
|
||||
rm -rf "$OUTDIR"
|
||||
mkdir -p "$OUTDIR"
|
||||
|
||||
# Place info about the current commit into the build dir to easily identify releases
|
||||
npm ls -depth -1 | head -n 1 | cut -d' ' -f 1 > "$OUTDIR"/release.txt
|
||||
date >> "$OUTDIR"/release.txt
|
||||
git rev-parse HEAD >> "$OUTDIR"/release.txt
|
||||
|
||||
# Place a json schema for the file format into the build directory too
|
||||
node scripts/generate-file-format-schema-json.js > "$OUTDIR"/file-format-schema.json
|
||||
|
||||
# Include licenses
|
||||
# https://github.com/jlfwong/speedscope/pull/412
|
||||
cp assets/source-code-pro/LICENSE.md "$OUTDIR"/source-code-pro.LICENSE.md
|
||||
|
||||
node_modules/.bin/tsx scripts/build-release.ts --outdir "$OUTDIR" --protocol "$PROTOCOL"
|
||||
@@ -5,11 +5,11 @@
|
||||
|
||||
set -euxo pipefail
|
||||
|
||||
TMPDIR=`mktemp -d -t speedscope-test-installation`
|
||||
TESTDIR=`mktemp -d -t speedscope-test-installation`
|
||||
PACKEDNAME=`npm pack | tail -n1`
|
||||
|
||||
mv "$PACKEDNAME" "$TMPDIR"
|
||||
cd "$TMPDIR"
|
||||
mv "$PACKEDNAME" "$TESTDIR"
|
||||
cd "$TESTDIR"
|
||||
tar -xvvf "$PACKEDNAME"
|
||||
cd package
|
||||
npm install
|
||||
@@ -17,4 +17,4 @@ npm install
|
||||
set +x
|
||||
echo
|
||||
echo "Run the following command to switch into the test directory"
|
||||
echo cd "$TMPDIR"/package
|
||||
echo cd "$TESTDIR"/package
|
||||
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
+80
@@ -0,0 +1,80 @@
|
||||
#!/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
|
||||
|
||||
# Typecheck
|
||||
node_modules/.bin/tsc --noEmit
|
||||
|
||||
# Run unit tests
|
||||
npm run jest
|
||||
|
||||
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
|
||||
|
||||
# Deploy the website
|
||||
npm run deploy
|
||||
|
||||
# Create a new release on Github
|
||||
"$script_dir/prepare-zip-file.sh"
|
||||
|
||||
# Don't double echo the below commands
|
||||
set +x
|
||||
|
||||
echo
|
||||
echo
|
||||
echo "Visit https://github.com/jlfwong/speedscope/releases/new to create a new release."
|
||||
echo
|
||||
echo "tag: $tagname"
|
||||
echo "title: $tagname"
|
||||
echo "attachment: dist/release/speedscope-$version.zip"
|
||||
echo "$changelog_update"
|
||||
|
||||
# NOTE: This part is almost-but-not-quite-automatable using a command like this:
|
||||
#
|
||||
# gh release create "$tagname" --title "$tagname" --notes "$changelog_update"
|
||||
# --attach "dist/release/speedscope-$version.zip"
|
||||
#
|
||||
# There are two problems.
|
||||
#
|
||||
# 1. The "--attach" flag doesn't exit
|
||||
# 2. I don't want the changelog notes to include the version and date like they do in CHANGELOG.md
|
||||
#
|
||||
# If 1. was solveable, then 2. would be easy to work-around.
|
||||
@@ -102,7 +102,10 @@ export class FlamechartColorPassRenderer {
|
||||
private material: Graphics.Material
|
||||
private buffer: Graphics.VertexBuffer
|
||||
|
||||
constructor(private gl: Graphics.Context, theme: Theme) {
|
||||
constructor(
|
||||
private gl: Graphics.Context,
|
||||
theme: Theme,
|
||||
) {
|
||||
const vertices = [
|
||||
{pos: [-1, 1], uv: [0, 1]},
|
||||
{pos: [1, 1], uv: [1, 1]},
|
||||
|
||||
@@ -70,7 +70,10 @@ export class ViewportRectangleRenderer {
|
||||
private material: Graphics.Material
|
||||
private buffer: Graphics.VertexBuffer
|
||||
|
||||
constructor(private gl: Graphics.Context, theme: Theme) {
|
||||
constructor(
|
||||
private gl: Graphics.Context,
|
||||
theme: Theme,
|
||||
) {
|
||||
const vertices = [
|
||||
[-1, 1],
|
||||
[1, 1],
|
||||
|
||||
@@ -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 [
|
||||
|
||||
@@ -99,10 +99,332 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy allocations profile 2`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":example_app (40414)",
|
||||
"line": undefined,
|
||||
"name": "example_app (40414)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":start",
|
||||
"line": undefined,
|
||||
"name": "start",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":main",
|
||||
"line": undefined,
|
||||
"name": "main",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":std::rt::lang_start::hdba6f1ebfd1bdcf8",
|
||||
"line": undefined,
|
||||
"name": "std::rt::lang_start::hdba6f1ebfd1bdcf8",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":std::rt::lang_start_internal::hc453db0ee48af82e",
|
||||
"line": undefined,
|
||||
"name": "std::rt::lang_start_internal::hc453db0ee48af82e",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c",
|
||||
"line": undefined,
|
||||
"name": "std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc",
|
||||
"line": undefined,
|
||||
"name": "std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8",
|
||||
"line": undefined,
|
||||
"name": "core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":example_app::main::hddab13ae8d8b6a6e",
|
||||
"line": undefined,
|
||||
"name": "example_app::main::hddab13ae8d8b6a6e",
|
||||
"selfWeight": 1385999000,
|
||||
"totalWeight": 96000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":example_app::example_a::h622d6879b734496d",
|
||||
"line": undefined,
|
||||
"name": "example_app::example_a::h622d6879b734496d",
|
||||
"selfWeight": 282000000,
|
||||
"totalWeight": 47000000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":std::time::Instant::elapsed::h2e3793148fc23529",
|
||||
"line": undefined,
|
||||
"name": "std::time::Instant::elapsed::h2e3793148fc23529",
|
||||
"selfWeight": 2000000000,
|
||||
"totalWeight": 93081000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":mach_absolute_time",
|
||||
"line": undefined,
|
||||
"name": "mach_absolute_time",
|
||||
"selfWeight": 91080000000,
|
||||
"totalWeight": 91080000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":DYLD-STUB$$mach_absolute_time",
|
||||
"line": undefined,
|
||||
"name": "DYLD-STUB$$mach_absolute_time",
|
||||
"selfWeight": 1000000,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":core::time::Duration::as_millis::hae6ad1b9cf7bb5ec",
|
||||
"line": undefined,
|
||||
"name": "core::time::Duration::as_millis::hae6ad1b9cf7bb5ec",
|
||||
"selfWeight": 1249000000,
|
||||
"totalWeight": 1249000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":example_app::example_b::h71b31fcd89b9ffd2",
|
||||
"line": undefined,
|
||||
"name": "example_app::example_b::h71b31fcd89b9ffd2",
|
||||
"selfWeight": 1000000,
|
||||
"totalWeight": 84000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":example_app::example_c::h631759c10d7dee93",
|
||||
"line": undefined,
|
||||
"name": "example_app::example_c::h631759c10d7dee93",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alloc::vec::Vec$LT$T$C$A$GT$::push::ha3426502ffc42c8b",
|
||||
"line": undefined,
|
||||
"name": "alloc::vec::Vec$LT$T$C$A$GT$::push::ha3426502ffc42c8b",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alloc::raw_vec::RawVec$LT$T$C$A$GT$::reserve_for_push::he4a29b8274e35dbb",
|
||||
"line": undefined,
|
||||
"name": "alloc::raw_vec::RawVec$LT$T$C$A$GT$::reserve_for_push::he4a29b8274e35dbb",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alloc::raw_vec::RawVec$LT$T$C$A$GT$::grow_amortized::h78db9ba423623c58",
|
||||
"line": undefined,
|
||||
"name": "alloc::raw_vec::RawVec$LT$T$C$A$GT$::grow_amortized::h78db9ba423623c58",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alloc::raw_vec::finish_grow::h876f5af1c66d74c8",
|
||||
"line": undefined,
|
||||
"name": "alloc::raw_vec::finish_grow::h876f5af1c66d74c8",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$::allocate::hcc733a40a34fbc94",
|
||||
"line": undefined,
|
||||
"name": "_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$::allocate::hcc733a40a34fbc94",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alloc::alloc::Global::alloc_impl::hc55feba7d6266dfa",
|
||||
"line": undefined,
|
||||
"name": "alloc::alloc::Global::alloc_impl::hc55feba7d6266dfa",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alloc::alloc::alloc::hfac63f3d6850b759",
|
||||
"line": undefined,
|
||||
"name": "alloc::alloc::alloc::hfac63f3d6850b759",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_malloc_zone_malloc",
|
||||
"line": undefined,
|
||||
"name": "_malloc_zone_malloc",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":nanov2_malloc",
|
||||
"line": undefined,
|
||||
"name": "nanov2_malloc",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":nanov2_allocate",
|
||||
"line": undefined,
|
||||
"name": "nanov2_allocate",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":nanov2_find_block_and_allocate",
|
||||
"line": undefined,
|
||||
"name": "nanov2_find_block_and_allocate",
|
||||
"selfWeight": 1000000,
|
||||
"totalWeight": 1000000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":std::io::stdio::_print::hdecfefdeb43586ed",
|
||||
"line": undefined,
|
||||
"name": "std::io::stdio::_print::hdecfefdeb43586ed",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_$LT$$RF$std..io..stdio..Stdout$u20$as$u20$std..io..Write$GT$::write_fmt::h2cb06dcd2b172844",
|
||||
"line": undefined,
|
||||
"name": "_$LT$$RF$std..io..stdio..Stdout$u20$as$u20$std..io..Write$GT$::write_fmt::h2cb06dcd2b172844",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":core::fmt::write::hed96bcfc6342aee5",
|
||||
"line": undefined,
|
||||
"name": "core::fmt::write::hed96bcfc6342aee5",
|
||||
"selfWeight": 468,
|
||||
"totalWeight": 1000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_$LT$std..io..Write..write_fmt..Adapter$LT$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::hbe33ec23de24ce2f",
|
||||
"line": undefined,
|
||||
"name": "_$LT$std..io..Write..write_fmt..Adapter$LT$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::hbe33ec23de24ce2f",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 532,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_$LT$std..io..stdio..StdoutLock$u20$as$u20$std..io..Write$GT$::write_all::h22667d0a03b2151b",
|
||||
"line": undefined,
|
||||
"name": "_$LT$std..io..stdio..StdoutLock$u20$as$u20$std..io..Write$GT$::write_all::h22667d0a03b2151b",
|
||||
"selfWeight": 532,
|
||||
"totalWeight": 532,
|
||||
},
|
||||
],
|
||||
"name": "cycles-example-deep-copy.txt",
|
||||
"stacks": Array [
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;std::time::Instant::elapsed::h2e3793148fc23529;mach_absolute_time 750000:00",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;std::time::Instant::elapsed::h2e3793148fc23529;std::time::Instant::elapsed::h2e3793148fc23529 10000:00",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;std::time::Instant::elapsed::h2e3793148fc23529;DYLD-STUB$$mach_absolute_time 16:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;std::time::Instant::elapsed::h2e3793148fc23529 6650:00",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;core::time::Duration::as_millis::hae6ad1b9cf7bb5ec 10566:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;example_app::example_a::h622d6879b734496d 3016:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;example_app::example_b::h71b31fcd89b9ffd2;std::time::Instant::elapsed::h2e3793148fc23529;mach_absolute_time 1333:20",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;example_app::example_b::h71b31fcd89b9ffd2;std::time::Instant::elapsed::h2e3793148fc23529;std::time::Instant::elapsed::h2e3793148fc23529 16:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;example_app::example_b::h71b31fcd89b9ffd2;example_app::example_c::h631759c10d7dee93;alloc::vec::Vec$LT$T$C$A$GT$::push::ha3426502ffc42c8b;alloc::raw_vec::RawVec$LT$T$C$A$GT$::reserve_for_push::he4a29b8274e35dbb;alloc::raw_vec::RawVec$LT$T$C$A$GT$::grow_amortized::h78db9ba423623c58;alloc::raw_vec::finish_grow::h876f5af1c66d74c8;_$LT$alloc..alloc..Global$u20$as$u20$core..alloc..Allocator$GT$::allocate::hcc733a40a34fbc94;alloc::alloc::Global::alloc_impl::hc55feba7d6266dfa;alloc::alloc::alloc::hfac63f3d6850b759;_malloc_zone_malloc;nanov2_malloc;nanov2_allocate;nanov2_allocate;nanov2_find_block_and_allocate 16:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;example_app::example_b::h71b31fcd89b9ffd2;example_app::example_b::h71b31fcd89b9ffd2 16:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d;example_app::example_b::h71b31fcd89b9ffd2;core::time::Duration::as_millis::hae6ad1b9cf7bb5ec 16:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::example_a::h622d6879b734496d 1683:20",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;std::time::Instant::elapsed::h2e3793148fc23529;mach_absolute_time 766666:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;std::time::Instant::elapsed::h2e3793148fc23529;std::time::Instant::elapsed::h2e3793148fc23529 10816:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;std::time::Instant::elapsed::h2e3793148fc23529 5850:00",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;core::time::Duration::as_millis::hae6ad1b9cf7bb5ec 10233:20",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;example_app::main::hddab13ae8d8b6a6e 3166:40",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;std::io::stdio::_print::hdecfefdeb43586ed;_$LT$$RF$std..io..stdio..Stdout$u20$as$u20$std..io..Write$GT$::write_fmt::h2cb06dcd2b172844;core::fmt::write::hed96bcfc6342aee5;_$LT$std..io..Write..write_fmt..Adapter$LT$T$GT$$u20$as$u20$core..fmt..Write$GT$::write_str::hbe33ec23de24ce2f;_$LT$std..io..stdio..StdoutLock$u20$as$u20$std..io..Write$GT$::write_all::h22667d0a03b2151b 532.00ms",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e;std::io::stdio::_print::hdecfefdeb43586ed;_$LT$$RF$std..io..stdio..Stdout$u20$as$u20$std..io..Write$GT$::write_fmt::h2cb06dcd2b172844;core::fmt::write::hed96bcfc6342aee5 468.00ms",
|
||||
"example_app (40414);start;main;std::rt::lang_start::hdba6f1ebfd1bdcf8;std::rt::lang_start_internal::hc453db0ee48af82e;std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd856f2663871206c;std::sys_common::backtrace::__rust_begin_short_backtrace::h4869fd82068bc1dc;core::ops::function::FnOnce::call_once::h06e0c27ee740c6a8;example_app::main::hddab13ae8d8b6a6e 19933:19",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy allocations profile: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy allocations profile: indexToView 2`] = `0`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy allocations profile: profileGroup.name 1`] = `"random-allocations-deep-copy.txt"`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy allocations profile: profileGroup.name 2`] = `"cycles-example-deep-copy.txt"`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy time profile 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -332,6 +654,504 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy time profile, version 16 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":start",
|
||||
"line": undefined,
|
||||
"name": "start",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4479,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":main",
|
||||
"line": undefined,
|
||||
"name": "main",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4475,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":delta()",
|
||||
"line": undefined,
|
||||
"name": "delta()",
|
||||
"selfWeight": 395,
|
||||
"totalWeight": 2000,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":alpha()",
|
||||
"line": undefined,
|
||||
"name": "alpha()",
|
||||
"selfWeight": 1574,
|
||||
"totalWeight": 1600,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":leakMemory()",
|
||||
"line": undefined,
|
||||
"name": "leakMemory()",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 65,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":szone_malloc_should_clear",
|
||||
"line": undefined,
|
||||
"name": "szone_malloc_should_clear",
|
||||
"selfWeight": 7,
|
||||
"totalWeight": 49,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":small_malloc_should_clear",
|
||||
"line": undefined,
|
||||
"name": "small_malloc_should_clear",
|
||||
"selfWeight": 20,
|
||||
"totalWeight": 44,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":small_malloc_from_free_list",
|
||||
"line": undefined,
|
||||
"name": "small_malloc_from_free_list",
|
||||
"selfWeight": 20,
|
||||
"totalWeight": 20,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_malloc_zone_malloc",
|
||||
"line": undefined,
|
||||
"name": "_malloc_zone_malloc",
|
||||
"selfWeight": 14,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":beta()",
|
||||
"line": undefined,
|
||||
"name": "beta()",
|
||||
"selfWeight": 1602,
|
||||
"totalWeight": 1629,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":rack_get_thread_index",
|
||||
"line": undefined,
|
||||
"name": "rack_get_thread_index",
|
||||
"selfWeight": 6,
|
||||
"totalWeight": 6,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":nanov2_malloc_type",
|
||||
"line": undefined,
|
||||
"name": "nanov2_malloc_type",
|
||||
"selfWeight": 6,
|
||||
"totalWeight": 6,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":DYLD-STUB$$malloc",
|
||||
"line": undefined,
|
||||
"name": "DYLD-STUB$$malloc",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":mvm_allocate_pages_plat",
|
||||
"line": undefined,
|
||||
"name": "mvm_allocate_pages_plat",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_kernelrpc_mach_vm_map_trap",
|
||||
"line": undefined,
|
||||
"name": "_kernelrpc_mach_vm_map_trap",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":gamma()",
|
||||
"line": undefined,
|
||||
"name": "gamma()",
|
||||
"selfWeight": 827,
|
||||
"totalWeight": 838,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::start(dyld4::KernelArgs*, void*, void*)::$_0::operator()() const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::start(dyld4::KernelArgs*, void*, void*)::$_0::operator()() const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*)",
|
||||
"line": undefined,
|
||||
"name": "dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&)",
|
||||
"line": undefined,
|
||||
"name": "dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":mach_o::Header::forEachLoadCommand(void (load_command const*, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "mach_o::Header::forEachLoadCommand(void (load_command const*, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":invocation function for block in mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "invocation function for block in mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":invocation function for block in dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&)",
|
||||
"line": undefined,
|
||||
"name": "invocation function for block in dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&)",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::forEachPath(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer)",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::forEachPath(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::ProcessConfig::PathOverrides::forEachPathVariant(char const*, dyld3::Platform, bool, bool, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::ProcessConfig::PathOverrides::forEachPathVariant(char const*, dyld3::Platform, bool, bool, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::forEachResolvedAtPathVar(dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, dyld4::ProcessConfig::PathOverrides::Type, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer)",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::forEachResolvedAtPathVar(dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, dyld4::ProcessConfig::PathOverrides::Type, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":invocation function for block in dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&)",
|
||||
"line": undefined,
|
||||
"name": "invocation function for block in dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::makeDyldCacheLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, unsigned int, mach_o::Layout const*)",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::makeDyldCacheLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, unsigned int, mach_o::Layout const*)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::RuntimeState::findPrebuiltLoader(char const*) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::RuntimeState::findPrebuiltLoader(char const*) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::PrebuiltLoader::isValid(dyld4::RuntimeState const&) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::PrebuiltLoader::isValid(dyld4::RuntimeState const&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":invocation function for block in dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const",
|
||||
"line": undefined,
|
||||
"name": "invocation function for block in dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::SyscallDelegate::fileExists(char const*, dyld4::FileID*, int*) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::SyscallDelegate::fileExists(char const*, dyld4::FileID*, int*) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld3::stat(char const*, stat*)",
|
||||
"line": undefined,
|
||||
"name": "dyld3::stat(char const*, stat*)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":stat",
|
||||
"line": undefined,
|
||||
"name": "stat",
|
||||
"selfWeight": 3,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::APIs::runAllInitializersForMain()",
|
||||
"line": undefined,
|
||||
"name": "dyld4::APIs::runAllInitializersForMain()",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::operator()() const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::operator()() const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::PrebuiltLoader::runInitializers(dyld4::RuntimeState&) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::PrebuiltLoader::runInitializers(dyld4::RuntimeState&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const",
|
||||
"line": undefined,
|
||||
"name": "dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const",
|
||||
"line": undefined,
|
||||
"name": "dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const",
|
||||
"line": undefined,
|
||||
"name": "invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const",
|
||||
"line": undefined,
|
||||
"name": "invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": ":_GLOBAL__sub_I_stdlib_typed_new.cpp",
|
||||
"line": undefined,
|
||||
"name": "_GLOBAL__sub_I_stdlib_typed_new.cpp",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
],
|
||||
"name": "simple-time-profile-deep-copy.txt",
|
||||
"stacks": Array [
|
||||
"start;main;delta();alpha();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;small_malloc_from_free_list 2.00ms",
|
||||
"start;main;delta();alpha();leakMemory();szone_malloc_should_clear;small_malloc_should_clear 4.00ms",
|
||||
"start;main;delta();alpha();leakMemory();szone_malloc_should_clear;small_malloc_from_free_list 1.00ms",
|
||||
"start;main;delta();alpha();leakMemory();szone_malloc_should_clear 1.00ms",
|
||||
"start;main;delta();alpha();leakMemory();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;delta();alpha();_malloc_zone_malloc 2.00ms",
|
||||
"start;main;delta();alpha() 786.00ms",
|
||||
"start;main;delta();beta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;small_malloc_from_free_list 5.00ms",
|
||||
"start;main;delta();beta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;rack_get_thread_index 1.00ms",
|
||||
"start;main;delta();beta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear 3.00ms",
|
||||
"start;main;delta();beta();leakMemory();szone_malloc_should_clear 2.00ms",
|
||||
"start;main;delta();beta();leakMemory();nanov2_malloc_type 1.00ms",
|
||||
"start;main;delta();beta();leakMemory();DYLD-STUB$$malloc 1.00ms",
|
||||
"start;main;delta();beta();leakMemory() 1.00ms",
|
||||
"start;main;delta();beta();nanov2_malloc_type 2.00ms",
|
||||
"start;main;delta();beta();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;delta();beta() 778.00ms",
|
||||
"start;main;delta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;mvm_allocate_pages_plat;_kernelrpc_mach_vm_map_trap 1.00ms",
|
||||
"start;main;delta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear 3.00ms",
|
||||
"start;main;delta();leakMemory();szone_malloc_should_clear 3.00ms",
|
||||
"start;main;delta();leakMemory();small_malloc_should_clear 2.00ms",
|
||||
"start;main;delta();leakMemory();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;delta();_malloc_zone_malloc 3.00ms",
|
||||
"start;main;delta() 395.00ms",
|
||||
"start;main;gamma();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;small_malloc_from_free_list 3.00ms",
|
||||
"start;main;gamma();leakMemory();szone_malloc_should_clear;small_malloc_should_clear 1.00ms",
|
||||
"start;main;gamma();leakMemory();szone_malloc_should_clear;rack_get_thread_index 1.00ms",
|
||||
"start;main;gamma();leakMemory();small_malloc_should_clear 1.00ms",
|
||||
"start;main;gamma();leakMemory();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;gamma();leakMemory();nanov2_malloc_type 1.00ms",
|
||||
"start;main;gamma();leakMemory() 1.00ms",
|
||||
"start;main;gamma();_malloc_zone_malloc 2.00ms",
|
||||
"start;main;gamma() 827.00ms",
|
||||
"start;main;beta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;small_malloc_from_free_list 4.00ms",
|
||||
"start;main;beta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;rack_get_thread_index 1.00ms",
|
||||
"start;main;beta();leakMemory();szone_malloc_should_clear;small_malloc_should_clear 1.00ms",
|
||||
"start;main;beta();leakMemory();szone_malloc_should_clear;rack_get_thread_index 1.00ms",
|
||||
"start;main;beta();leakMemory();nanov2_malloc_type 1.00ms",
|
||||
"start;main;beta();leakMemory();small_malloc_should_clear 1.00ms",
|
||||
"start;main;beta();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;beta() 824.00ms",
|
||||
"start;main;alpha();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;small_malloc_from_free_list 5.00ms",
|
||||
"start;main;alpha();leakMemory();szone_malloc_should_clear;small_malloc_should_clear;rack_get_thread_index 2.00ms",
|
||||
"start;main;alpha();leakMemory();szone_malloc_should_clear;small_malloc_should_clear 3.00ms",
|
||||
"start;main;alpha();leakMemory();szone_malloc_should_clear 1.00ms",
|
||||
"start;main;alpha();leakMemory();nanov2_malloc_type 1.00ms",
|
||||
"start;main;alpha();leakMemory();small_malloc_should_clear 1.00ms",
|
||||
"start;main;alpha();leakMemory();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;alpha();_malloc_zone_malloc 1.00ms",
|
||||
"start;main;alpha() 788.00ms",
|
||||
"start;dyld4::start(dyld4::KernelArgs*, void*, void*)::$_0::operator()() const;dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*);dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&);mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const;mach_o::Header::forEachLoadCommand(void (load_command const*, bool&) block_pointer) const;invocation function for block in mach_o::Header::forEachLinkedDylib(void (char const*, mach_o::LinkedDylibAttributes, mach_o::Version32, mach_o::Version32, bool&) block_pointer) const;invocation function for block in dyld4::JustInTimeLoader::loadDependents(Diagnostics&, dyld4::RuntimeState&, dyld4::Loader::LoadOptions const&);dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&);dyld4::Loader::forEachPath(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer);dyld4::ProcessConfig::PathOverrides::forEachPathVariant(char const*, dyld3::Platform, bool, bool, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer) const;dyld4::Loader::forEachResolvedAtPathVar(dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, dyld4::ProcessConfig::PathOverrides::Type, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer);invocation function for block in dyld4::Loader::getLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&);dyld4::Loader::makeDyldCacheLoader(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::LoadOptions const&, unsigned int, mach_o::Layout const*);dyld4::RuntimeState::findPrebuiltLoader(char const*) const;dyld4::PrebuiltLoader::isValid(dyld4::RuntimeState const&) const;dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const;dyld4::ProcessConfig::PathOverrides::forEachPathVariant(char const*, dyld3::Platform, bool, bool, bool&, void (char const*, dyld4::ProcessConfig::PathOverrides::Type, bool&) block_pointer) const;invocation function for block in dyld4::PrebuiltLoader::invalidateInIsolation(dyld4::RuntimeState const&) const;dyld4::SyscallDelegate::fileExists(char const*, dyld4::FileID*, int*) const;dyld3::stat(char const*, stat*);stat 3.00ms",
|
||||
"start;dyld4::start(dyld4::KernelArgs*, void*, void*)::$_0::operator()() const;dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*);dyld4::APIs::runAllInitializersForMain();dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const;dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::operator()() const;dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const;dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const;dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const;dyld4::PrebuiltLoader::runInitializers(dyld4::RuntimeState&) const;dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const;dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const;dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const;dyld3::MachOFile::forEachLoadCommand(Diagnostics&, void (load_command const*, bool&) block_pointer) const;invocation function for block in dyld3::MachOFile::forEachSection(void (dyld3::MachOFile::SectionInfo const&, bool, bool&) block_pointer) const;invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const;_GLOBAL__sub_I_stdlib_typed_new.cpp 1.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy time profile, version 16: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy time profile, version 16: profileGroup.name 1`] = `"simple-time-profile-deep-copy.txt"`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy time profile: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromInstrumentsDeepCopy time profile: profileGroup.name 1`] = `"simple-time-profile-deep-copy.txt"`;
|
||||
|
||||
@@ -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"`;
|
||||
|
||||
@@ -172,6 +172,68 @@ exports[`importTraceEvents bad E events: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents bad E events: profileGroup.name 1`] = `"too-many-end-events.json"`;
|
||||
|
||||
exports[`importTraceEvents different number of start and end calls to same function at same timestamp 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "anonymous",
|
||||
"line": undefined,
|
||||
"name": "anonymous",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "anonymous {\\"parent\\":1}",
|
||||
"line": undefined,
|
||||
"name": "anonymous {\\"parent\\":1}",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function1 {\\"parent\\":2}",
|
||||
"line": undefined,
|
||||
"name": "function1 {\\"parent\\":2}",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 2,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "anonymous {\\"parent\\":3}",
|
||||
"line": undefined,
|
||||
"name": "anonymous {\\"parent\\":3}",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 2,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "anonymous {\\"parent\\":8}",
|
||||
"line": undefined,
|
||||
"name": "anonymous {\\"parent\\":8}",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 2,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"anonymous 1.00µs",
|
||||
"anonymous;anonymous {\\"parent\\":1};function1 {\\"parent\\":2};anonymous {\\"parent\\":3} 2.00µs",
|
||||
"anonymous;anonymous {\\"parent\\":1};anonymous {\\"parent\\":8} 2.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents different number of start and end calls to same function at same timestamp: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents different number of start and end calls to same function at same timestamp: profileGroup.name 1`] = `"simultaneous-anonymous-calls.json"`;
|
||||
|
||||
exports[`importTraceEvents end event with empty stack 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -342,6 +404,41 @@ exports[`importTraceEvents event reordering name match: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents event reordering name match: profileGroup.name 1`] = `"event-reordering-name-match.json"`;
|
||||
|
||||
exports[`importTraceEvents hermes profile with multiple frames 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": null,
|
||||
"file": null,
|
||||
"key": "[root]:null:null:null",
|
||||
"line": null,
|
||||
"name": "[root]",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": 12,
|
||||
"file": "/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"key": "beta:/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js:54:12",
|
||||
"line": 54,
|
||||
"name": "beta",
|
||||
"selfWeight": 12,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"[root] 1.00µs",
|
||||
"[root];beta 12.00µs",
|
||||
"[root] 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents hermes profile with multiple frames: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents hermes profile with multiple frames: profileGroup.name 1`] = `"simple-hermes.json"`;
|
||||
|
||||
exports[`importTraceEvents invalid x nesting 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -468,6 +565,81 @@ exports[`importTraceEvents mismatched name: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents mismatched name: profileGroup.name 1`] = `"mismatched-name.json"`;
|
||||
|
||||
exports[`importTraceEvents multi-thread profile with samples 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "[root]:root",
|
||||
"line": undefined,
|
||||
"name": "[root]",
|
||||
"selfWeight": 20770,
|
||||
"totalWeight": 34096,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function1:JavaScript",
|
||||
"line": undefined,
|
||||
"name": "function1",
|
||||
"selfWeight": 13326,
|
||||
"totalWeight": 13326,
|
||||
},
|
||||
],
|
||||
"name": "hermes (pid 7512), mqt_js (tid 1)",
|
||||
"stacks": Array [
|
||||
"[root] 20.77ms",
|
||||
"[root];function1 13.33ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multi-thread profile with samples 2`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "[root thread 2]:root",
|
||||
"line": undefined,
|
||||
"name": "[root thread 2]",
|
||||
"selfWeight": 30770,
|
||||
"totalWeight": 54096,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function3:JavaScript",
|
||||
"line": undefined,
|
||||
"name": "function3",
|
||||
"selfWeight": 13326,
|
||||
"totalWeight": 13326,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function4:Metadata",
|
||||
"line": undefined,
|
||||
"name": "function4",
|
||||
"selfWeight": 10000,
|
||||
"totalWeight": 10000,
|
||||
},
|
||||
],
|
||||
"name": "hermes (pid 7512, tid 2)",
|
||||
"stacks": Array [
|
||||
"[root thread 2] 20.77ms",
|
||||
"[root thread 2];function3 13.33ms",
|
||||
"[root thread 2];function4 10.00ms",
|
||||
"[root thread 2] 10.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents multi-thread profile with samples: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents multi-thread profile with samples: profileGroup.name 1`] = `"multi-thread-with-samples.json"`;
|
||||
|
||||
exports[`importTraceEvents multiprocess 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -1178,6 +1350,41 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents simple hermes profile 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": null,
|
||||
"file": null,
|
||||
"key": "[root]:null:null:null",
|
||||
"line": null,
|
||||
"name": "[root]",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": 12,
|
||||
"file": "/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js",
|
||||
"key": "beta:/Users/example/test_project/node_modules/metro-runtime/src/polyfills/require.js:54:12",
|
||||
"line": 54,
|
||||
"name": "beta",
|
||||
"selfWeight": 12,
|
||||
"totalWeight": 12,
|
||||
},
|
||||
],
|
||||
"name": "pid 0, tid 0",
|
||||
"stacks": Array [
|
||||
"[root] 1.00µs",
|
||||
"[root];beta 12.00µs",
|
||||
"[root] 1.00µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents simple hermes profile: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents simple hermes profile: profileGroup.name 1`] = `"simple-hermes.json"`;
|
||||
|
||||
exports[`importTraceEvents simple object 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
@@ -1224,6 +1431,70 @@ exports[`importTraceEvents simple object: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents simple object: profileGroup.name 1`] = `"simple-object.json"`;
|
||||
|
||||
exports[`importTraceEvents simple profile with samples 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "[root]:root",
|
||||
"line": undefined,
|
||||
"name": "[root]",
|
||||
"selfWeight": 30779,
|
||||
"totalWeight": 64710,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function1(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:1:1):JavaScript",
|
||||
"line": undefined,
|
||||
"name": "function1(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:1:1)",
|
||||
"selfWeight": 13326,
|
||||
"totalWeight": 13326,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function2(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:418874:4):JavaScript",
|
||||
"line": undefined,
|
||||
"name": "function2(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:418874:4)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 10605,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "function3(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:17:3):JavaScript",
|
||||
"line": undefined,
|
||||
"name": "function3(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:17:3)",
|
||||
"selfWeight": 10605,
|
||||
"totalWeight": 10605,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "[GC Young Gen]:Metadata",
|
||||
"line": undefined,
|
||||
"name": "[GC Young Gen]",
|
||||
"selfWeight": 10000,
|
||||
"totalWeight": 10000,
|
||||
},
|
||||
],
|
||||
"name": "hermes (pid 7512), mqt_js (tid 7695)",
|
||||
"stacks": Array [
|
||||
"[root] 20.77ms",
|
||||
"[root];function1(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:1:1) 13.33ms",
|
||||
"[root];function2(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:418874:4);function3(http://localhost:8081/index.bundle?platform=android&dev=false&minify=false&app=org.toshi&modulesOnly=false&runModule=true:17:3) 10.61ms",
|
||||
"[root] 10.01ms",
|
||||
"[root];[GC Young Gen] 10.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importTraceEvents simple profile with samples: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents simple profile with samples: profileGroup.name 1`] = `"simple-with-samples.json"`;
|
||||
|
||||
exports[`importTraceEvents simple: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importTraceEvents simple: profileGroup.name 1`] = `"simple.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')
|
||||
})
|
||||
|
||||
+177
-58
@@ -95,7 +95,10 @@ class CallGraph {
|
||||
private totalWeights = new Map<Frame, number>()
|
||||
private childrenTotalWeights = new Map<Frame, Map<Frame, number>>()
|
||||
|
||||
constructor(private fileName: string, private fieldName: string) {}
|
||||
constructor(
|
||||
private fileName: string,
|
||||
private fieldName: string,
|
||||
) {}
|
||||
|
||||
private getOrInsertFrame(info: FrameInfo): Frame {
|
||||
return Frame.getOrInsert(this.frameSet, info)
|
||||
@@ -129,26 +132,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 +153,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 +186,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 +208,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()
|
||||
@@ -292,8 +348,11 @@ class CallgrindParser {
|
||||
private savedFileNames: {[id: string]: string} = {}
|
||||
private savedFunctionNames: {[id: string]: string} = {}
|
||||
|
||||
constructor(contents: TextFileContent, private importedFileName: string) {
|
||||
this.lines = contents.splitLines()
|
||||
constructor(
|
||||
contents: TextFileContent,
|
||||
private importedFileName: string,
|
||||
) {
|
||||
this.lines = [...contents.splitLines()]
|
||||
this.lineNum = 0
|
||||
}
|
||||
|
||||
@@ -344,7 +403,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 +443,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 +467,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 +484,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 +545,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 +624,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.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// The bits of this API that we care about. This is implemented by WebKitEntry
|
||||
// https://wicg.github.io/entries-api/#api-entry
|
||||
export interface FileSystemDirectoryReader {
|
||||
readEntries(cb: (entries: FileSystemEntry[]) => void, error: (err: Error) => void): void
|
||||
}
|
||||
export interface FileSystemEntry {
|
||||
readonly isFile: boolean
|
||||
readonly isDirectory: boolean
|
||||
readonly name: string
|
||||
readonly fullPath: string
|
||||
}
|
||||
export interface FileSystemDirectoryEntry extends FileSystemEntry {
|
||||
createReader(): FileSystemDirectoryReader
|
||||
}
|
||||
export interface FileSystemFileEntry extends FileSystemEntry {
|
||||
file(cb: (file: File) => void, errCb: (err: Error) => void): void
|
||||
}
|
||||
+13
-1
@@ -1,11 +1,11 @@
|
||||
import {Profile, ProfileGroup} from '../lib/profile'
|
||||
import {FileSystemDirectoryEntry} from './file-system-entry'
|
||||
|
||||
import {
|
||||
importFromChromeCPUProfile,
|
||||
importFromChromeTimeline,
|
||||
isChromeTimeline,
|
||||
importFromOldV8CPUProfile,
|
||||
isChromeTimelineObject,
|
||||
} from './chrome'
|
||||
import {importFromStackprof} from './stackprof'
|
||||
import {importFromInstrumentsDeepCopy, importFromInstrumentsTrace} from './instruments'
|
||||
@@ -22,6 +22,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 +93,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 +140,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 +188,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')
|
||||
|
||||
@@ -3,7 +3,6 @@ import * as path from 'path'
|
||||
import {dumpProfile, checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
import * as JSZip from 'jszip'
|
||||
import {FileSystemEntry} from './file-system-entry'
|
||||
import {importFromFileSystemDirectoryEntry} from '.'
|
||||
|
||||
describe('importFromInstrumentsDeepCopy', () => {
|
||||
@@ -13,14 +12,27 @@ describe('importFromInstrumentsDeepCopy', () => {
|
||||
)
|
||||
})
|
||||
|
||||
test('time profile, version 16', async () => {
|
||||
await checkProfileSnapshot(
|
||||
'./sample/profiles/Instruments/16.0/simple-time-profile-deep-copy.txt',
|
||||
)
|
||||
})
|
||||
|
||||
test('allocations profile', async () => {
|
||||
await checkProfileSnapshot(
|
||||
'./sample/profiles/Instruments/7.3.1/random-allocations-deep-copy.txt',
|
||||
)
|
||||
})
|
||||
|
||||
test('allocations profile', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Instruments/13.4/cycles-example-deep-copy.txt')
|
||||
})
|
||||
})
|
||||
|
||||
class ZipBackedFileSystemEntry implements FileSystemEntry {
|
||||
// This is a bit of a weird type signature. I'm making this almost a
|
||||
// FileSystemEntry, but ignoring the parts of the API I don't use anywhere and
|
||||
// are a pain to implement.
|
||||
class ZipBackedFileSystemEntry implements Omit<FileSystemEntry, 'filesystem' | 'getParent'> {
|
||||
readonly isFile: boolean
|
||||
readonly isDirectory: boolean
|
||||
readonly name: string
|
||||
@@ -29,7 +41,10 @@ class ZipBackedFileSystemEntry implements FileSystemEntry {
|
||||
private zipDir: any | null
|
||||
private zipFile: JSZip.JSZipObject | null
|
||||
|
||||
constructor(private zip: JSZip, fullPath: string) {
|
||||
constructor(
|
||||
private zip: JSZip,
|
||||
fullPath: string,
|
||||
) {
|
||||
this.fullPath = fullPath
|
||||
|
||||
this.zipFile = zip.file(fullPath)
|
||||
@@ -69,7 +84,7 @@ class ZipBackedFileSystemEntry implements FileSystemEntry {
|
||||
const ret: FileSystemEntry[] = []
|
||||
this.zipDir.forEach((relativePath: string, file: {name: string}) => {
|
||||
if (relativePath.split('/').length === (relativePath.endsWith('/') ? 2 : 1)) {
|
||||
ret.push(new ZipBackedFileSystemEntry(this.zip, file.name))
|
||||
ret.push(new ZipBackedFileSystemEntry(this.zip, file.name) as any as FileSystemEntry)
|
||||
}
|
||||
})
|
||||
cb(ret)
|
||||
@@ -86,7 +101,10 @@ describe('importFromInstrumentsTrace', () => {
|
||||
JSZip.loadAsync(data).then(resolve)
|
||||
})
|
||||
})
|
||||
const root = new ZipBackedFileSystemEntry(zip, 'simple-time-profile.trace')
|
||||
const root: FileSystemDirectoryEntry = new ZipBackedFileSystemEntry(
|
||||
zip,
|
||||
'simple-time-profile.trace',
|
||||
) as any
|
||||
const profileGroup = await importFromFileSystemDirectoryEntry(root)
|
||||
const profile = profileGroup.profiles[profileGroup.indexToView]
|
||||
expect(dumpProfile(profile)).toMatchSnapshot()
|
||||
|
||||
@@ -10,11 +10,10 @@ import {
|
||||
} from '../lib/profile'
|
||||
import {sortBy, getOrThrow, getOrInsert, lastOf, getOrElse, zeroPad} from '../lib/utils'
|
||||
import {ByteFormatter, TimeFormatter} from '../lib/value-formatters'
|
||||
import {FileSystemDirectoryEntry, FileSystemEntry, FileSystemFileEntry} from './file-system-entry'
|
||||
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 []
|
||||
@@ -39,12 +38,14 @@ interface PastedTimeProfileRow {
|
||||
Weight?: string
|
||||
'Source Path'?: string
|
||||
'Symbol Name'?: string
|
||||
'Symbol Names'?: string
|
||||
}
|
||||
|
||||
interface PastedAllocationsProfileRow {
|
||||
'Bytes Used'?: string
|
||||
'Source Path'?: string
|
||||
'Symbol Name'?: string
|
||||
'Symbol Names'?: string
|
||||
}
|
||||
|
||||
interface FrameInfoWithWeight extends FrameInfo {
|
||||
@@ -85,7 +86,16 @@ function getWeight(deepCopyRow: any): number {
|
||||
case 's':
|
||||
return 1000 * value
|
||||
case 'min':
|
||||
return 60 * 1000 * value
|
||||
|
||||
case 'cycles':
|
||||
return value
|
||||
case 'Kc':
|
||||
return 1000 * value
|
||||
case 'Mc':
|
||||
return 1000 * 1000 * value
|
||||
case 'Gc':
|
||||
return 1000 * 1000 * 1000 * value
|
||||
}
|
||||
throw new Error(`Unrecognized units ${units}`)
|
||||
}
|
||||
@@ -100,9 +110,12 @@ export function importFromInstrumentsDeepCopy(contents: TextFileContent): Profil
|
||||
|
||||
const stack: FrameInfoWithWeight[] = []
|
||||
let cumulativeValue: number = 0
|
||||
let leadingFirstRowSpaces: number = rows[0]['Symbol Names']
|
||||
? rows[0]['Symbol Names'].lastIndexOf(' ') + 1
|
||||
: 0
|
||||
|
||||
for (let row of rows) {
|
||||
const symbolName = row['Symbol Name']
|
||||
const symbolName = row['Symbol Name'] || row['Symbol Names']?.slice(leadingFirstRowSpaces)
|
||||
if (!symbolName) continue
|
||||
const trimmedSymbolName = symbolName.trim()
|
||||
let stackDepth = symbolName.length - trimmedSymbolName.length
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
+38
-5
@@ -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,12 @@ 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)
|
||||
|
||||
if (sampleTypeIndex < 0 || sampleTypeIndex >= sampleTypes.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const sampleType = sampleTypes[sampleTypeIndex]
|
||||
|
||||
const profileBuilder = new StackListProfileBuilder()
|
||||
@@ -126,7 +154,12 @@ export function importAsPprofProfile(rawProfile: ArrayBuffer): Profile | null {
|
||||
for (let s of protoProfile.sample) {
|
||||
const stack = s.locationId ? s.locationId.map(l => frameByLocationID.get(i32(l))) : []
|
||||
stack.reverse()
|
||||
const value = s.value![sampleTypeIndex]
|
||||
|
||||
if (s.value == null || s.value.length <= sampleTypeIndex) {
|
||||
return null
|
||||
}
|
||||
|
||||
const value = s.value[sampleTypeIndex]
|
||||
profileBuilder.appendSampleWithWeight(stack.filter(f => f != null) as FrameInfo[], +value)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {readFileSync} from 'fs'
|
||||
import {importProfileGroupFromText} from '.'
|
||||
import {checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
test('importFromStackprof', async () => {
|
||||
@@ -7,3 +9,32 @@ 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()
|
||||
}
|
||||
|
||||
@@ -47,6 +47,10 @@ test('importTraceEvents bad E events', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/too-many-end-events.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents different number of start and end calls to same function at same timestamp', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simultaneous-anonymous-calls.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents event re-ordering', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/must-retain-original-order.json')
|
||||
})
|
||||
@@ -118,3 +122,19 @@ test('importTraceEvents invalid x nesting', async () => {
|
||||
test('importTraceEvents event reordering name match', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/event-reordering-name-match.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents simple hermes profile', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-hermes.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents hermes profile with multiple frames', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-hermes.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents simple profile with samples', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/simple-with-samples.json')
|
||||
})
|
||||
|
||||
test('importTraceEvents multi-thread profile with samples', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/trace-event/multi-thread-with-samples.json')
|
||||
})
|
||||
|
||||
+455
-148
@@ -1,5 +1,11 @@
|
||||
import {sortBy, zeroPad, getOrInsert, lastOf} from '../lib/utils'
|
||||
import {ProfileGroup, CallTreeProfileBuilder, FrameInfo, Profile} from '../lib/profile'
|
||||
import {
|
||||
ProfileGroup,
|
||||
CallTreeProfileBuilder,
|
||||
FrameInfo,
|
||||
Profile,
|
||||
StackListProfileBuilder,
|
||||
} from '../lib/profile'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
|
||||
// This file concerns import from the "Trace Event Format", authored by Google
|
||||
@@ -42,12 +48,46 @@ interface TraceEvent {
|
||||
cat?: string
|
||||
|
||||
// Any arguments provided for the event. Some of the event types have required argument fields, otherwise, you can put any information you wish in here. The arguments are displayed in Trace Viewer when you view an event in the analysis section.
|
||||
args: any
|
||||
args?: any
|
||||
|
||||
// A fixed color name to associate with the event. If provided, cname must be one of the names listed in trace-viewer's base color scheme's reserved color names list
|
||||
cname?: string
|
||||
}
|
||||
|
||||
enum ExporterSource {
|
||||
HERMES = 'HERMES',
|
||||
UNKNOWN = 'UNKNOWN',
|
||||
}
|
||||
|
||||
interface HermesTraceEventArgs {
|
||||
line: number | null
|
||||
column: number | null
|
||||
funcLine?: string | null
|
||||
funcColumn?: string | null
|
||||
name: string
|
||||
category: string
|
||||
parent?: number
|
||||
url: string | null
|
||||
params: string | null
|
||||
allocatedCategory: string
|
||||
allocatedName: string
|
||||
}
|
||||
|
||||
const requiredHermesArguments: Array<keyof HermesTraceEventArgs> = [
|
||||
'line',
|
||||
'column',
|
||||
'name',
|
||||
'category',
|
||||
'url',
|
||||
'params',
|
||||
'allocatedCategory',
|
||||
'allocatedName',
|
||||
]
|
||||
|
||||
type HermesTraceEvent = TraceEvent & {
|
||||
args: HermesTraceEventArgs
|
||||
}
|
||||
|
||||
interface BTraceEvent extends TraceEvent {
|
||||
ph: 'B'
|
||||
}
|
||||
@@ -65,16 +105,53 @@ interface XTraceEvent extends TraceEvent {
|
||||
// The trace format supports a number of event types that we ignore.
|
||||
type ImportableTraceEvent = BTraceEvent | ETraceEvent | XTraceEvent
|
||||
|
||||
interface StackFrame {
|
||||
line: string
|
||||
column: string
|
||||
funcLine: string
|
||||
funcColumn: string
|
||||
name: string
|
||||
category: string
|
||||
// A parent function may or may not exist
|
||||
parent?: number
|
||||
}
|
||||
|
||||
interface Sample {
|
||||
cpu: string
|
||||
name: string
|
||||
ts: string
|
||||
pid: number
|
||||
tid: string
|
||||
weight: string
|
||||
// Will refer to an element in the stackFrames object
|
||||
sf: number
|
||||
stackFrameData?: StackFrame
|
||||
}
|
||||
|
||||
interface TraceWithSamples {
|
||||
traceEvents: TraceEvent[]
|
||||
samples: Sample[]
|
||||
stackFrames: {[key: string]: StackFrame}
|
||||
}
|
||||
|
||||
interface TraceEventObject {
|
||||
traceEvents: TraceEvent[]
|
||||
}
|
||||
|
||||
type Trace = TraceEvent[] | TraceEventObject | TraceWithSamples
|
||||
|
||||
function pidTidKey(pid: number, tid: number): string {
|
||||
// We zero-pad the PID and TID to make sorting them by pid/tid pair later easier.
|
||||
return `${zeroPad('' + pid, 10)}:${zeroPad('' + tid, 10)}`
|
||||
}
|
||||
|
||||
function partitionByPidTid(events: ImportableTraceEvent[]): Map<string, ImportableTraceEvent[]> {
|
||||
const map = new Map<string, ImportableTraceEvent[]>()
|
||||
function partitionByPidTid<T extends {tid: number | string; pid: number | string}>(
|
||||
events: T[],
|
||||
): Map<string, T[]> {
|
||||
const map = new Map<string, T[]>()
|
||||
|
||||
for (let ev of events) {
|
||||
const list = getOrInsert(map, pidTidKey(ev.pid, ev.tid), () => [])
|
||||
const list = getOrInsert(map, pidTidKey(Number(ev.pid), Number(ev.tid)), () => [])
|
||||
list.push(ev)
|
||||
}
|
||||
|
||||
@@ -103,12 +180,12 @@ function selectQueueToTakeFromNext(
|
||||
// If we got here, the 'B' event queue and the 'E' event queue have events at
|
||||
// the front with equal timestamps.
|
||||
|
||||
// If the front of the 'E' queue matches the front of the 'B' queue by name,
|
||||
// If the front of the 'E' queue matches the front of the 'B' queue by key,
|
||||
// then it means we have a zero duration event. Process the 'B' queue first
|
||||
// to ensure it opens before we try to close it.
|
||||
//
|
||||
// Otherwise, process the 'E' queue first.
|
||||
return bFront.name === eFront.name ? 'B' : 'E'
|
||||
return getEventId(bFront) === getEventId(eFront) ? 'B' : 'E'
|
||||
}
|
||||
|
||||
function convertToEventQueues(events: ImportableTraceEvent[]): [BTraceEvent[], ETraceEvent[]] {
|
||||
@@ -228,126 +305,221 @@ function getThreadNamesByPidTid(events: TraceEvent[]): Map<string, string> {
|
||||
return threadNameByPidTid
|
||||
}
|
||||
|
||||
function keyForEvent(event: TraceEvent): string {
|
||||
let name = `${event.name || '(unnamed)'}`
|
||||
if (event.args) {
|
||||
name += ` ${JSON.stringify(event.args)}`
|
||||
}
|
||||
return name
|
||||
function getEventName(event: TraceEvent): string {
|
||||
return `${event.name || '(unnamed)'}`
|
||||
}
|
||||
|
||||
function frameInfoForEvent(event: TraceEvent): FrameInfo {
|
||||
const key = keyForEvent(event)
|
||||
/**
|
||||
* Attempt to construct a unique identifier for an event. Note that this
|
||||
* is different from the frame key, as in some cases we don't want to include
|
||||
* some arguments to allow from frame grouping (e.g. parent in the case of
|
||||
* hermes profiles)
|
||||
*/
|
||||
function getEventId(event: TraceEvent): string {
|
||||
let key = getEventName(event)
|
||||
if (event.args) {
|
||||
key += ` ${JSON.stringify(event.args)}`
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
function frameInfoForEvent(
|
||||
event: TraceEvent,
|
||||
exporterSource: ExporterSource = ExporterSource.UNKNOWN,
|
||||
): FrameInfo {
|
||||
// In Hermes profiles we have additional guaranteed metadata we can use to
|
||||
// more accurately populate profiles with info such as line + col number
|
||||
if (exporterSource === ExporterSource.HERMES) {
|
||||
const hermesFrameKey = `${event.name}:${event.args.url}:${event.args.line}:${event.args.column}`
|
||||
|
||||
return {
|
||||
name: getEventName(event),
|
||||
key: hermesFrameKey,
|
||||
file: event.args.url,
|
||||
line: event.args.line,
|
||||
col: event.args.column,
|
||||
}
|
||||
}
|
||||
|
||||
const key = getEventId(event)
|
||||
|
||||
return {
|
||||
name: key,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
const importableEvents = filterIgnoredEventTypes(events)
|
||||
const partitioned = partitionByPidTid(importableEvents)
|
||||
function getProfileName(
|
||||
processName: string | undefined,
|
||||
threadName: string | undefined,
|
||||
pid: number,
|
||||
tid: number,
|
||||
): string {
|
||||
if (processName != null && threadName != null) {
|
||||
return `${processName} (pid ${pid}), ${threadName} (tid ${tid})`
|
||||
} else if (processName != null) {
|
||||
return `${processName} (pid ${pid}, tid ${tid})`
|
||||
} else if (threadName != null) {
|
||||
return `${threadName} (pid ${pid}, tid ${tid})`
|
||||
} else {
|
||||
return `pid ${pid}, tid ${tid}`
|
||||
}
|
||||
}
|
||||
|
||||
function getProfileNamesFromSamples(
|
||||
events: TraceEvent[],
|
||||
partitionedSamples: Map<string, Sample[]>,
|
||||
): Map<string, string> {
|
||||
const processNamesByPid = getProcessNamesByPid(events)
|
||||
const threadNamesByPidTid = getThreadNamesByPidTid(events)
|
||||
|
||||
const profilePairs: [string, Profile][] = []
|
||||
const profileNamesByPidTid = new Map<string, string>()
|
||||
|
||||
partitioned.forEach(eventsForThread => {
|
||||
if (eventsForThread.length === 0) return
|
||||
partitionedSamples.forEach(samples => {
|
||||
if (samples.length === 0) return
|
||||
|
||||
const {pid, tid} = eventsForThread[0]
|
||||
|
||||
const profile = new CallTreeProfileBuilder()
|
||||
profile.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
const pid = Number(samples[0].pid)
|
||||
const tid = Number(samples[0].tid)
|
||||
|
||||
const profileKey = pidTidKey(pid, tid)
|
||||
const processName = processNamesByPid.get(pid)
|
||||
const threadName = threadNamesByPidTid.get(pidTidKey(pid, tid))
|
||||
const threadName = threadNamesByPidTid.get(profileKey)
|
||||
const profileName = getProfileName(processName, threadName, pid, tid)
|
||||
|
||||
if (processName != null && threadName != null) {
|
||||
profile.setName(`${processName} (pid ${pid}), ${threadName} (tid ${tid})`)
|
||||
} else if (processName != null) {
|
||||
profile.setName(`${processName} (pid ${pid}, tid ${tid})`)
|
||||
} else if (threadName != null) {
|
||||
profile.setName(`${threadName} (pid ${pid}, tid ${tid})`)
|
||||
} else {
|
||||
profile.setName(`pid ${pid}, tid ${tid}`)
|
||||
profileNamesByPidTid.set(profileKey, profileName)
|
||||
})
|
||||
|
||||
return profileNamesByPidTid
|
||||
}
|
||||
|
||||
function getProfileNamesFromTraceEvents(
|
||||
events: TraceEvent[],
|
||||
partitionedTraceEvents: Map<string, TraceEvent[]>,
|
||||
): Map<string, string> {
|
||||
const processNamesByPid = getProcessNamesByPid(events)
|
||||
const threadNamesByPidTid = getThreadNamesByPidTid(events)
|
||||
|
||||
const profileNamesByPidTid = new Map<string, string>()
|
||||
|
||||
partitionedTraceEvents.forEach(importableEvents => {
|
||||
if (importableEvents.length === 0) return
|
||||
|
||||
const {pid, tid} = importableEvents[0]
|
||||
|
||||
const profileKey = pidTidKey(pid, tid)
|
||||
const processName = processNamesByPid.get(pid)
|
||||
const threadName = threadNamesByPidTid.get(profileKey)
|
||||
const profileName = getProfileName(processName, threadName, pid, tid)
|
||||
|
||||
profileNamesByPidTid.set(profileKey, profileName)
|
||||
})
|
||||
|
||||
return profileNamesByPidTid
|
||||
}
|
||||
|
||||
function eventListToProfile(
|
||||
importableEvents: ImportableTraceEvent[],
|
||||
name: string,
|
||||
exporterSource: ExporterSource = ExporterSource.UNKNOWN,
|
||||
): Profile {
|
||||
// The trace event format is hard to deal with because it specifically
|
||||
// allows events to be recorded out of order, *but* event ordering is still
|
||||
// important for events with the same timestamp. Because of this, rather
|
||||
// than thinking about the entire event stream as a single queue of events,
|
||||
// we're going to first construct two time-ordered lists of events:
|
||||
//
|
||||
// 1. ts ordered queue of 'B' events
|
||||
// 2. ts ordered queue of 'E' events
|
||||
//
|
||||
// We deal with 'X' events by converting them to one entry in the 'B' event
|
||||
// queue and one entry in the 'E' event queue.
|
||||
//
|
||||
// The high level goal is to deal with 'B' events in 'ts' order, breaking
|
||||
// ties by the order the events occurred in the file, and deal with 'E'
|
||||
// events in 'ts' order, breaking ties in whatever order causes the 'E'
|
||||
// events to match whatever is on the top of the stack.
|
||||
const [bEventQueue, eEventQueue] = convertToEventQueues(importableEvents)
|
||||
|
||||
const profileBuilder = new CallTreeProfileBuilder()
|
||||
profileBuilder.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
profileBuilder.setName(name)
|
||||
|
||||
const frameStack: BTraceEvent[] = []
|
||||
const enterFrame = (b: BTraceEvent) => {
|
||||
frameStack.push(b)
|
||||
profileBuilder.enterFrame(frameInfoForEvent(b, exporterSource), b.ts)
|
||||
}
|
||||
|
||||
const tryToLeaveFrame = (e: ETraceEvent) => {
|
||||
const b = lastOf(frameStack)
|
||||
|
||||
if (b == null) {
|
||||
console.warn(
|
||||
`Tried to end frame "${
|
||||
frameInfoForEvent(e, exporterSource).key
|
||||
}", but the stack was empty. Doing nothing instead.`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// The trace event format is hard to deal with because it specifically
|
||||
// allows events to be recorded out of order, *but* event ordering is still
|
||||
// important for events with the same timestamp. Because of this, rather
|
||||
// than thinking about the entire event stream as a single queue of events,
|
||||
// we're going to first construct two time-ordered lists of events:
|
||||
//
|
||||
// 1. ts ordered queue of 'B' events
|
||||
// 2. ts ordered queue of 'E' events
|
||||
//
|
||||
// We deal with 'X' events by converting them to one entry in the 'B' event
|
||||
// queue and one entry in the 'E' event queue.
|
||||
//
|
||||
// The high level goal is to deal with 'B' events in 'ts' order, breaking
|
||||
// ties by the order the events occurred in the file, and deal with 'E'
|
||||
// events in 'ts' order, breaking ties in whatever order causes the 'E'
|
||||
// events to match whatever is on the top of the stack.
|
||||
const [bEventQueue, eEventQueue] = convertToEventQueues(eventsForThread)
|
||||
const eFrameInfo = frameInfoForEvent(e, exporterSource)
|
||||
const bFrameInfo = frameInfoForEvent(b, exporterSource)
|
||||
|
||||
const frameStack: BTraceEvent[] = []
|
||||
const enterFrame = (b: BTraceEvent) => {
|
||||
frameStack.push(b)
|
||||
profile.enterFrame(frameInfoForEvent(b), b.ts)
|
||||
if (e.name !== b.name) {
|
||||
console.warn(
|
||||
`ts=${e.ts}: Tried to end "${eFrameInfo.key}" when "${bFrameInfo.key}" was on the top of the stack. Doing nothing instead.`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const tryToLeaveFrame = (e: ETraceEvent) => {
|
||||
const b = lastOf(frameStack)
|
||||
|
||||
if (b == null) {
|
||||
console.warn(
|
||||
`Tried to end frame "${
|
||||
frameInfoForEvent(e).key
|
||||
}", but the stack was empty. Doing nothing instead.`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const eFrameInfo = frameInfoForEvent(e)
|
||||
const bFrameInfo = frameInfoForEvent(b)
|
||||
|
||||
if (e.name !== b.name) {
|
||||
console.warn(
|
||||
`ts=${e.ts}: Tried to end "${eFrameInfo.key}" when "${bFrameInfo.key}" was on the top of the stack. Doing nothing instead.`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (eFrameInfo.key !== bFrameInfo.key) {
|
||||
console.warn(
|
||||
`ts=${e.ts}: Tried to end "${eFrameInfo.key}" when "${bFrameInfo.key}" was on the top of the stack. Ending ${bFrameInfo.key} instead.`,
|
||||
)
|
||||
}
|
||||
|
||||
frameStack.pop()
|
||||
profile.leaveFrame(bFrameInfo, e.ts)
|
||||
if (eFrameInfo.key !== bFrameInfo.key) {
|
||||
console.warn(
|
||||
`ts=${e.ts}: Tried to end "${eFrameInfo.key}" when "${bFrameInfo.key}" was on the top of the stack. Ending ${bFrameInfo.key} instead.`,
|
||||
)
|
||||
}
|
||||
|
||||
while (bEventQueue.length > 0 || eEventQueue.length > 0) {
|
||||
const queueName = selectQueueToTakeFromNext(bEventQueue, eEventQueue)
|
||||
switch (queueName) {
|
||||
case 'B': {
|
||||
enterFrame(bEventQueue.shift()!)
|
||||
break
|
||||
}
|
||||
case 'E': {
|
||||
// Before we take the first event in the 'E' queue, let's first see if
|
||||
// there are any e events that exactly match the top of the stack.
|
||||
// We'll prioritize first by key, then by name if we can't find a key
|
||||
// match.
|
||||
const stackTop = lastOf(frameStack)
|
||||
if (stackTop != null) {
|
||||
const bFrameInfo = frameInfoForEvent(stackTop)
|
||||
frameStack.pop()
|
||||
profileBuilder.leaveFrame(bFrameInfo, e.ts)
|
||||
}
|
||||
|
||||
let swapped: boolean = false
|
||||
while (bEventQueue.length > 0 || eEventQueue.length > 0) {
|
||||
const queueName = selectQueueToTakeFromNext(bEventQueue, eEventQueue)
|
||||
switch (queueName) {
|
||||
case 'B': {
|
||||
enterFrame(bEventQueue.shift()!)
|
||||
break
|
||||
}
|
||||
case 'E': {
|
||||
// Before we take the first event in the 'E' queue, let's first see if
|
||||
// there are any e events that exactly match the top of the stack.
|
||||
// We'll prioritize first by key, then by name if we can't find a key
|
||||
// match.
|
||||
const stackTop = lastOf(frameStack)
|
||||
if (stackTop != null) {
|
||||
const bFrameInfo = frameInfoForEvent(stackTop, exporterSource)
|
||||
|
||||
let swapped: boolean = false
|
||||
|
||||
for (let i = 1; i < eEventQueue.length; i++) {
|
||||
const eEvent = eEventQueue[i]
|
||||
if (eEvent.ts > eEventQueue[0].ts) {
|
||||
// Only consider 'E' events with the same ts as the front of the queue.
|
||||
break
|
||||
}
|
||||
|
||||
const eFrameInfo = frameInfoForEvent(eEvent, exporterSource)
|
||||
if (bFrameInfo.key === eFrameInfo.key) {
|
||||
// We have a match! Process this one first.
|
||||
const temp = eEventQueue[0]
|
||||
eEventQueue[0] = eEventQueue[i]
|
||||
eEventQueue[i] = temp
|
||||
swapped = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!swapped) {
|
||||
// There was no key match, let's see if we can find a name match
|
||||
for (let i = 1; i < eEventQueue.length; i++) {
|
||||
const eEvent = eEventQueue[i]
|
||||
if (eEvent.ts > eEventQueue[0].ts) {
|
||||
@@ -355,8 +527,7 @@ function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
break
|
||||
}
|
||||
|
||||
const eFrameInfo = frameInfoForEvent(eEvent)
|
||||
if (bFrameInfo.key === eFrameInfo.key) {
|
||||
if (eEvent.name === stackTop.name) {
|
||||
// We have a match! Process this one first.
|
||||
const temp = eEventQueue[0]
|
||||
eEventQueue[0] = eEventQueue[i]
|
||||
@@ -365,50 +536,160 @@ function eventListToProfileGroup(events: TraceEvent[]): ProfileGroup {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (!swapped) {
|
||||
// There was no key match, let's see if we can find a name match
|
||||
for (let i = 1; i < eEventQueue.length; i++) {
|
||||
const eEvent = eEventQueue[i]
|
||||
if (eEvent.ts > eEventQueue[0].ts) {
|
||||
// Only consider 'E' events with the same ts as the front of the queue.
|
||||
break
|
||||
}
|
||||
|
||||
if (eEvent.name === stackTop.name) {
|
||||
// We have a match! Process this one first.
|
||||
const temp = eEventQueue[0]
|
||||
eEventQueue[0] = eEventQueue[i]
|
||||
eEventQueue[i] = temp
|
||||
swapped = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If swapped is still false at this point, it means we're about to
|
||||
// pop a stack frame that doesn't even match by name. Bummer.
|
||||
}
|
||||
|
||||
const e = eEventQueue.shift()!
|
||||
|
||||
tryToLeaveFrame(e)
|
||||
break
|
||||
// If swapped is still false at this point, it means we're about to
|
||||
// pop a stack frame that doesn't even match by name. Bummer.
|
||||
}
|
||||
|
||||
default:
|
||||
const _exhaustiveCheck: never = queueName
|
||||
return _exhaustiveCheck
|
||||
const e = eEventQueue.shift()!
|
||||
|
||||
tryToLeaveFrame(e)
|
||||
break
|
||||
}
|
||||
|
||||
default:
|
||||
const _exhaustiveCheck: never = queueName
|
||||
return _exhaustiveCheck
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = frameStack.length - 1; i >= 0; i--) {
|
||||
const frame = frameInfoForEvent(frameStack[i], exporterSource)
|
||||
console.warn(`Frame "${frame.key}" was still open at end of profile. Closing automatically.`)
|
||||
profileBuilder.leaveFrame(frame, profileBuilder.getTotalWeight())
|
||||
}
|
||||
|
||||
return profileBuilder.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array containing the time difference in microseconds between the current
|
||||
* sample and the next sample
|
||||
*/
|
||||
function getTimeDeltasForSamples(samples: Sample[]): number[] {
|
||||
const timeDeltas: number[] = []
|
||||
let lastTimeStamp = Number(samples[0].ts)
|
||||
|
||||
samples.forEach((sample: Sample, idx: number) => {
|
||||
if (idx === 0) return
|
||||
|
||||
const timeDiff = Number(sample.ts) - lastTimeStamp
|
||||
lastTimeStamp = Number(sample.ts)
|
||||
timeDeltas.push(timeDiff)
|
||||
})
|
||||
|
||||
timeDeltas.push(0)
|
||||
|
||||
return timeDeltas
|
||||
}
|
||||
|
||||
/**
|
||||
* The chrome json trace event spec only specifies name and category
|
||||
* as required stack frame properties
|
||||
*
|
||||
* https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview#heading=h.b4y98p32171
|
||||
*/
|
||||
function frameInfoForSampleFrame({name, category}: StackFrame): FrameInfo {
|
||||
return {
|
||||
key: `${name}:${category}`,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
function getActiveFramesForSample(
|
||||
stackFrames: {[key: string]: StackFrame},
|
||||
frameId: number,
|
||||
): FrameInfo[] {
|
||||
const frames = []
|
||||
let parent: number | undefined = frameId
|
||||
|
||||
while (parent) {
|
||||
const frame: StackFrame = stackFrames[parent]
|
||||
|
||||
if (!frame) {
|
||||
throw new Error(`Could not find frame for id ${parent}`)
|
||||
}
|
||||
|
||||
for (let i = frameStack.length - 1; i >= 0; i--) {
|
||||
const frame = frameInfoForEvent(frameStack[i])
|
||||
console.warn(`Frame "${frame.key}" was still open at end of profile. Closing automatically.`)
|
||||
profile.leaveFrame(frame, profile.getTotalWeight())
|
||||
frames.push(frameInfoForSampleFrame(frame))
|
||||
parent = frame.parent
|
||||
}
|
||||
|
||||
return frames.reverse()
|
||||
}
|
||||
|
||||
function sampleListToProfile(contents: TraceWithSamples, samples: Sample[], name: string): Profile {
|
||||
const profileBuilder = new StackListProfileBuilder()
|
||||
|
||||
profileBuilder.setValueFormatter(new TimeFormatter('microseconds'))
|
||||
profileBuilder.setName(name)
|
||||
|
||||
const timeDeltas = getTimeDeltasForSamples(samples)
|
||||
|
||||
samples.forEach((sample, index) => {
|
||||
const timeDelta = timeDeltas[index]
|
||||
const activeFrames = getActiveFramesForSample(contents.stackFrames, sample.sf)
|
||||
|
||||
profileBuilder.appendSampleWithWeight(activeFrames, timeDelta)
|
||||
})
|
||||
|
||||
return profileBuilder.build()
|
||||
}
|
||||
|
||||
function eventListToProfileGroup(
|
||||
events: TraceEvent[],
|
||||
exporterSource: ExporterSource = ExporterSource.UNKNOWN,
|
||||
): ProfileGroup {
|
||||
const importableEvents = filterIgnoredEventTypes(events)
|
||||
const partitionedTraceEvents = partitionByPidTid(importableEvents)
|
||||
const profileNamesByPidTid = getProfileNamesFromTraceEvents(events, partitionedTraceEvents)
|
||||
|
||||
const profilePairs: [string, Profile][] = []
|
||||
|
||||
profileNamesByPidTid.forEach((name, profileKey) => {
|
||||
const importableEventsForPidTid = partitionedTraceEvents.get(profileKey)
|
||||
|
||||
if (!importableEventsForPidTid) {
|
||||
throw new Error(`Could not find events for key: ${importableEventsForPidTid}`)
|
||||
}
|
||||
|
||||
profilePairs.push([pidTidKey(pid, tid), profile.build()])
|
||||
profilePairs.push([
|
||||
profileKey,
|
||||
eventListToProfile(importableEventsForPidTid, name, exporterSource),
|
||||
])
|
||||
})
|
||||
|
||||
// For now, we just sort processes by pid & tid.
|
||||
// TODO: The standard specifies that metadata events with the name
|
||||
// "process_sort_index" and "thread_sort_index" can be used to influence the
|
||||
// order, but for simplicity we'll ignore that until someone complains :)
|
||||
sortBy(profilePairs, p => p[0])
|
||||
|
||||
return {
|
||||
name: '',
|
||||
indexToView: 0,
|
||||
profiles: profilePairs.map(p => p[1]),
|
||||
}
|
||||
}
|
||||
|
||||
function sampleListToProfileGroup(contents: TraceWithSamples): ProfileGroup {
|
||||
const partitionedSamples = partitionByPidTid(contents.samples)
|
||||
const profileNamesByPidTid = getProfileNamesFromSamples(contents.traceEvents, partitionedSamples)
|
||||
|
||||
const profilePairs: [string, Profile][] = []
|
||||
|
||||
profileNamesByPidTid.forEach((name, profileKey) => {
|
||||
const samplesForPidTid = partitionedSamples.get(profileKey)
|
||||
|
||||
if (!samplesForPidTid) {
|
||||
throw new Error(`Could not find samples for key: ${samplesForPidTid}`)
|
||||
}
|
||||
|
||||
if (samplesForPidTid.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
profilePairs.push([profileKey, sampleListToProfile(contents, samplesForPidTid, name)])
|
||||
})
|
||||
|
||||
// For now, we just sort processes by pid & tid.
|
||||
@@ -456,27 +737,53 @@ function isTraceEventList(maybeEventList: any): maybeEventList is TraceEvent[] {
|
||||
return true
|
||||
}
|
||||
|
||||
function isTraceEventObject(
|
||||
maybeTraceEventObject: any,
|
||||
): maybeTraceEventObject is {traceEvents: TraceEvent[]} {
|
||||
function isHermesTraceEvent(traceEventArgs: any): traceEventArgs is HermesTraceEventArgs {
|
||||
if (!traceEventArgs) {
|
||||
return false
|
||||
}
|
||||
|
||||
return requiredHermesArguments.every(prop => prop in traceEventArgs)
|
||||
}
|
||||
|
||||
function isHermesTraceEventList(maybeEventList: any): maybeEventList is HermesTraceEvent[] {
|
||||
if (!isTraceEventList(maybeEventList)) return false
|
||||
|
||||
// We just check the first element to avoid iterating over all trace events,
|
||||
// and asumme that if the first one is formatted like a hermes profile then
|
||||
// all events will be
|
||||
return isHermesTraceEvent(maybeEventList[0].args)
|
||||
}
|
||||
|
||||
function isTraceEventObject(maybeTraceEventObject: any): maybeTraceEventObject is TraceEventObject {
|
||||
if (!('traceEvents' in maybeTraceEventObject)) return false
|
||||
return isTraceEventList(maybeTraceEventObject['traceEvents'])
|
||||
}
|
||||
|
||||
export function isTraceEventFormatted(
|
||||
rawProfile: any,
|
||||
): rawProfile is {traceEvents: TraceEvent[]} | TraceEvent[] {
|
||||
function isTraceEventWithSamples(
|
||||
maybeTraceEventObject: any,
|
||||
): maybeTraceEventObject is TraceWithSamples {
|
||||
return (
|
||||
'traceEvents' in maybeTraceEventObject &&
|
||||
'stackFrames' in maybeTraceEventObject &&
|
||||
'samples' in maybeTraceEventObject &&
|
||||
isTraceEventList(maybeTraceEventObject['traceEvents'])
|
||||
)
|
||||
}
|
||||
|
||||
export function isTraceEventFormatted(rawProfile: any): rawProfile is Trace {
|
||||
// We're only going to support the JSON formatted profiles for now.
|
||||
// The spec also discusses support for data embedded in ftrace supported data: https://lwn.net/Articles/365835/.
|
||||
|
||||
return isTraceEventObject(rawProfile) || isTraceEventList(rawProfile)
|
||||
}
|
||||
|
||||
export function importTraceEvents(
|
||||
rawProfile: {traceEvents: TraceEvent[]} | TraceEvent[],
|
||||
): ProfileGroup {
|
||||
if (isTraceEventObject(rawProfile)) {
|
||||
export function importTraceEvents(rawProfile: Trace): ProfileGroup {
|
||||
if (isTraceEventWithSamples(rawProfile)) {
|
||||
return sampleListToProfileGroup(rawProfile)
|
||||
} else if (isTraceEventObject(rawProfile)) {
|
||||
return eventListToProfileGroup(rawProfile.traceEvents)
|
||||
} else if (isHermesTraceEventList(rawProfile)) {
|
||||
return eventListToProfileGroup(rawProfile, ExporterSource.HERMES)
|
||||
} else if (isTraceEventList(rawProfile)) {
|
||||
return eventListToProfileGroup(rawProfile)
|
||||
} else {
|
||||
|
||||
+24
-12
@@ -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 {
|
||||
@@ -195,7 +204,10 @@ export class StringBackedTextFileContent implements TextFileContent {
|
||||
}
|
||||
|
||||
export class TextProfileDataSource implements ProfileDataSource {
|
||||
constructor(private fileName: string, private contents: string) {}
|
||||
constructor(
|
||||
private fileName: string,
|
||||
private contents: string,
|
||||
) {}
|
||||
async name() {
|
||||
return this.fileName
|
||||
}
|
||||
|
||||
@@ -87,8 +87,8 @@ function codeToFrameInfo(code: Code, v8log: V8LogProfile): FrameInfo {
|
||||
matches[1].length > 0
|
||||
? matches[1]
|
||||
: file
|
||||
? `(anonymous ${file.split('/').pop()}:${line})`
|
||||
: '(anonymous)'
|
||||
? `(anonymous ${file.split('/').pop()}:${line})`
|
||||
: '(anonymous)'
|
||||
return {
|
||||
key: name,
|
||||
name: functionName,
|
||||
|
||||
@@ -1,5 +1,59 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importSpeedscopeProfiles 0.0.1 evented profile (no pretty print) 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 0,
|
||||
"line": undefined,
|
||||
"name": "a",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 1,
|
||||
"line": undefined,
|
||||
"name": "b",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 2,
|
||||
"line": undefined,
|
||||
"name": "c",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 3,
|
||||
"line": undefined,
|
||||
"name": "d",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "simple.txt",
|
||||
"stacks": Array [
|
||||
"a;b;c 2",
|
||||
"a;b;d 4",
|
||||
"a;b;c 3",
|
||||
"a;b 5",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importSpeedscopeProfiles 0.0.1 evented profile (no pretty print): indexToView 1`] = `0`;
|
||||
|
||||
exports[`importSpeedscopeProfiles 0.0.1 evented profile (no pretty print): profileGroup.name 1`] = `"simple.txt"`;
|
||||
|
||||
exports[`importSpeedscopeProfiles 0.0.1 evented profile 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
|
||||
+7
-1
@@ -66,6 +66,8 @@ declare const module: any
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
;(window as any)['Atom'] = AtomDev = {}
|
||||
|
||||
/*
|
||||
TODO(jlfwong): Fix this
|
||||
module.hot.dispose(() => {
|
||||
if (AtomDev) {
|
||||
hotReloadStash = new Map()
|
||||
@@ -76,13 +78,17 @@ if (process.env.NODE_ENV === 'development') {
|
||||
|
||||
;(window as any)['Atom_hotReloadStash'] = hotReloadStash
|
||||
})
|
||||
*/
|
||||
|
||||
hotReloadStash = (window as any)['Atom_hotReloadStash'] || null
|
||||
}
|
||||
|
||||
export class Atom<T> {
|
||||
private observers: AtomListener[] = []
|
||||
constructor(protected state: T, debugKey: string) {
|
||||
constructor(
|
||||
protected state: T,
|
||||
debugKey: string,
|
||||
) {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
if (hotReloadStash?.has(debugKey)) {
|
||||
// If we have a stored value from a previous hot reload, use that
|
||||
|
||||
+8
-8
@@ -20,14 +20,14 @@ export class Color {
|
||||
hPrime < 1
|
||||
? [C, X, 0]
|
||||
: hPrime < 2
|
||||
? [X, C, 0]
|
||||
: hPrime < 3
|
||||
? [0, C, X]
|
||||
: hPrime < 4
|
||||
? [0, X, C]
|
||||
: hPrime < 5
|
||||
? [X, 0, C]
|
||||
: [C, 0, X]
|
||||
? [X, C, 0]
|
||||
: hPrime < 3
|
||||
? [0, C, X]
|
||||
: hPrime < 4
|
||||
? [0, X, C]
|
||||
: hPrime < 5
|
||||
? [X, 0, C]
|
||||
: [C, 0, X]
|
||||
|
||||
const m = L - (0.3 * R1 + 0.59 * G1 + 0.11 * B1)
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ export namespace FileFormat {
|
||||
unit: ValueUnit
|
||||
|
||||
// The starting value of the profile. This will typically be a timestamp.
|
||||
// All event values will be relative to this startValue.
|
||||
// All event values will be displayed relative to this startValue.
|
||||
startValue: number
|
||||
|
||||
// The final value of the profile. This will typically be a timestamp. This
|
||||
@@ -93,7 +93,7 @@ export namespace FileFormat {
|
||||
unit: ValueUnit
|
||||
|
||||
// The starting value of the profile. This will typically be a timestamp.
|
||||
// All event values will be relative to this startValue.
|
||||
// All event values will be displayed relative to this startValue.
|
||||
startValue: number
|
||||
|
||||
// The final value of the profile. This will typically be a timestamp. This
|
||||
|
||||
@@ -5,6 +5,12 @@ describe('importSpeedscopeProfiles', () => {
|
||||
await checkProfileSnapshot('./sample/profiles/speedscope/0.0.1/simple.speedscope.json')
|
||||
})
|
||||
|
||||
test('0.0.1 evented profile (no pretty print)', async () => {
|
||||
await checkProfileSnapshot(
|
||||
'./sample/profiles/speedscope/0.0.1/simple-no-pretty-print.speedscope.json',
|
||||
)
|
||||
})
|
||||
|
||||
test('0.1.2 sampled profile', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/speedscope/0.1.2/simple-sampled.speedscope.json')
|
||||
})
|
||||
|
||||
@@ -6,24 +6,11 @@
|
||||
// URL, but I want speedscope to work standalone offline. This means that the remaining
|
||||
// options require some way of having a local URL that corresponds the .wasm file.
|
||||
//
|
||||
// Also as of writing, speedscope is bundled with Parcel v1. Trying to import
|
||||
// a .wasm file in Parcel v1 tries to load the wasm module itself, which is not
|
||||
// what I'm trying to do -- I want SourceMapConsumer.initialize to be the thing
|
||||
// booting the WebAssembly, not Parcel itself.
|
||||
//
|
||||
// One way of getting around this problem is to modify the build system to
|
||||
// copy the .wasm file from node_modules/source-map/lib/mappings.wasm. I could do
|
||||
// this, but it's a bit of a pain.
|
||||
//
|
||||
// Another would be to use something like
|
||||
// import("url:../node_modules/source-map/lib/mappings.wasm"), and then pass the
|
||||
// resulting URL to SourceMapConsumer.initialize. This is also kind of a pain,
|
||||
// because I can only do that if I upgrade to Parcel v2. Ultimately, I'd like to
|
||||
// use esbuild rather than parcel at all, so for now I'm just punting on this by
|
||||
// using an old-version of source-map which doesn't depend on wasm.
|
||||
|
||||
// This is rarely used, so let's load it async to avoid bloating the initial
|
||||
// bundle.
|
||||
//
|
||||
// TODO(jlfwong): Revisit using the newer, wasm-based version of source-map now
|
||||
// that we're using esbuild for bundling.
|
||||
import type {MappingItem, RawSourceMap, SourceMapConsumer} from 'source-map'
|
||||
const sourceMapModule = import('source-map')
|
||||
|
||||
|
||||
+8
-2
@@ -5,7 +5,10 @@ export function clamp(x: number, minVal: number, maxVal: number) {
|
||||
}
|
||||
|
||||
export class Vec2 {
|
||||
constructor(readonly x: number, readonly y: number) {}
|
||||
constructor(
|
||||
readonly x: number,
|
||||
readonly y: number,
|
||||
) {}
|
||||
withX(x: number) {
|
||||
return new Vec2(x, this.y)
|
||||
}
|
||||
@@ -251,7 +254,10 @@ export class AffineTransform {
|
||||
}
|
||||
|
||||
export class Rect {
|
||||
constructor(readonly origin: Vec2, readonly size: Vec2) {}
|
||||
constructor(
|
||||
readonly origin: Vec2,
|
||||
readonly size: Vec2,
|
||||
) {}
|
||||
|
||||
isEmpty() {
|
||||
return this.width() == 0 || this.height() == 0
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import {exactMatchStrings} from './profile-search'
|
||||
|
||||
function assertMatch(text: string, pattern: string, expected: string) {
|
||||
const match = exactMatchStrings(text, pattern)
|
||||
|
||||
let highlighted = ''
|
||||
let last = 0
|
||||
for (let range of match) {
|
||||
highlighted += `${text.slice(last, range[0])}[${text.slice(range[0], range[1])}]`
|
||||
last = range[1]
|
||||
}
|
||||
highlighted += text.slice(last)
|
||||
|
||||
expect(highlighted).toEqual(expected)
|
||||
}
|
||||
|
||||
function assertNoMatch(text: string, pattern: string) {
|
||||
assertMatch(text, pattern, text)
|
||||
}
|
||||
|
||||
describe('exactMatchStrings', () => {
|
||||
test('no match', () => {
|
||||
assertNoMatch('a', 'b')
|
||||
assertNoMatch('aa', 'ab')
|
||||
assertNoMatch('a', 'aa')
|
||||
assertNoMatch('ca', 'ac')
|
||||
})
|
||||
|
||||
test('full text match', () => {
|
||||
assertMatch('hello', 'hello', '[hello]')
|
||||
assertMatch('multiple words', 'multiple words', '[multiple words]')
|
||||
})
|
||||
|
||||
test('case sensitivity', () => {
|
||||
assertMatch('HELLO', 'hello', '[HELLO]')
|
||||
assertMatch('Hello', 'hello', '[Hello]')
|
||||
assertMatch('hello', 'Hello', '[hello]')
|
||||
assertMatch('hello', 'HELLO', '[hello]')
|
||||
})
|
||||
|
||||
test('multiple occurrences', () => {
|
||||
assertMatch('hello hello', 'hello', '[hello] [hello]')
|
||||
assertMatch('hellohello', 'hello', '[hello][hello]')
|
||||
})
|
||||
|
||||
test('overlapping occurrences', () => {
|
||||
assertMatch('aaaaa', 'aa', '[aa][aa]a')
|
||||
assertMatch('abababa', 'aba', '[aba]b[aba]')
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,4 @@
|
||||
import {Profile, Frame, CallTreeNode} from './profile'
|
||||
import {FuzzyMatch, fuzzyMatchStrings} from './fuzzy-find'
|
||||
import {Flamechart, FlamechartFrame} from './flamechart'
|
||||
import {Rect, Vec2} from './math'
|
||||
|
||||
@@ -8,19 +7,50 @@ export enum FlamechartType {
|
||||
LEFT_HEAVY_FLAME_GRAPH,
|
||||
}
|
||||
|
||||
// In previous versions of speedscope, searching for strings within the profile
|
||||
// was done using fuzzy finding. As it turns out, this was surprising behavior
|
||||
// to most people, so we've switched to a more traditional substring search that
|
||||
// more closely mimics browser behavior.
|
||||
//
|
||||
// This is case insensitive for both the needle & the haystack. This means
|
||||
// searching for "hello" will match "Hello" and "HELLO", and searching for
|
||||
// "HELLO" will match both "hello" and "Hello". This matches Chrome's behavior
|
||||
// as far as I can tell.
|
||||
//
|
||||
// See https://github.com/jlfwong/speedscope/issues/352
|
||||
//
|
||||
// Return ranges for all matches in order to highlight them.
|
||||
export function exactMatchStrings(text: string, pattern: string): [number, number][] {
|
||||
const lowerText = text.toLocaleLowerCase()
|
||||
const lowerPattern = pattern.toLocaleLowerCase()
|
||||
|
||||
let lastIndex = 0
|
||||
const matchedRanges: Array<[number, number]> = []
|
||||
while (true) {
|
||||
let index = lowerText.indexOf(lowerPattern, lastIndex)
|
||||
if (index === -1) {
|
||||
return matchedRanges
|
||||
}
|
||||
matchedRanges.push([index, index + pattern.length])
|
||||
lastIndex = index + pattern.length
|
||||
}
|
||||
}
|
||||
|
||||
// A utility class for storing cached search results to avoid recomputation when
|
||||
// the search results & profile did not change.
|
||||
export class ProfileSearchResults {
|
||||
constructor(readonly profile: Profile, readonly searchQuery: string) {}
|
||||
constructor(
|
||||
readonly profile: Profile,
|
||||
readonly searchQuery: string,
|
||||
) {}
|
||||
|
||||
private matches: Map<Frame, FuzzyMatch> | null = null
|
||||
getMatchForFrame(frame: Frame): FuzzyMatch | null {
|
||||
private matches: Map<Frame, [number, number][] | null> | null = null
|
||||
getMatchForFrame(frame: Frame): [number, number][] | null {
|
||||
if (!this.matches) {
|
||||
this.matches = new Map()
|
||||
this.profile.forEachFrame(frame => {
|
||||
const match = fuzzyMatchStrings(frame.name, this.searchQuery)
|
||||
if (match == null) return
|
||||
this.matches!.set(frame, match)
|
||||
const match = exactMatchStrings(frame.name, this.searchQuery)
|
||||
this.matches!.set(frame, match.length === 0 ? null : match)
|
||||
})
|
||||
}
|
||||
return this.matches.get(frame) || null
|
||||
@@ -38,7 +68,10 @@ interface CachedFlamechartResult {
|
||||
}
|
||||
|
||||
export class FlamechartSearchResults {
|
||||
constructor(readonly flamechart: Flamechart, readonly profileResults: ProfileSearchResults) {}
|
||||
constructor(
|
||||
readonly flamechart: Flamechart,
|
||||
readonly profileResults: ProfileSearchResults,
|
||||
) {}
|
||||
|
||||
private matches: CachedFlamechartResult | null = null
|
||||
private getResults(): CachedFlamechartResult {
|
||||
|
||||
+9
-6
@@ -99,7 +99,10 @@ export class CallTreeNode extends HasWeights {
|
||||
this.frozen = true
|
||||
}
|
||||
|
||||
constructor(readonly frame: Frame, readonly parent: CallTreeNode | null) {
|
||||
constructor(
|
||||
readonly frame: Frame,
|
||||
readonly parent: CallTreeNode | null,
|
||||
) {
|
||||
super()
|
||||
}
|
||||
}
|
||||
@@ -439,14 +442,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 +502,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: {
|
||||
|
||||
+5
-1
@@ -76,7 +76,11 @@ class Panel {
|
||||
private GRAPH_WIDTH = 74 * PR
|
||||
private GRAPH_HEIGHT = 30 * PR
|
||||
|
||||
constructor(private name: string, private fg: string, private bg: string) {
|
||||
constructor(
|
||||
private name: string,
|
||||
private fg: string,
|
||||
private bg: string,
|
||||
) {
|
||||
this.canvas.width = this.WIDTH
|
||||
this.canvas.height = this.HEIGHT
|
||||
this.canvas.style.cssText = 'width:80px;height:48px'
|
||||
|
||||
@@ -105,6 +105,6 @@ export async function expectImportFailure(filepath: string) {
|
||||
await importProfilesFromArrayBuffer(path.basename(filepath), arrayBuffer)
|
||||
fail('Expected import to fail but it succeeded')
|
||||
} catch (error) {
|
||||
expect(error.message).toMatchSnapshot()
|
||||
expect((error as Error).message).toMatchSnapshot()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
+14
-4
@@ -42,7 +42,10 @@ test('getOrInsert', () => {
|
||||
})
|
||||
|
||||
class ValueType {
|
||||
private constructor(readonly a: string, readonly num: number) {}
|
||||
private constructor(
|
||||
readonly a: string,
|
||||
readonly num: number,
|
||||
) {}
|
||||
get key() {
|
||||
return `${this.a}_${this.num}`
|
||||
}
|
||||
@@ -247,11 +250,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('')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
+9
-11
@@ -213,17 +213,15 @@ export function lazyStatic<T>(cb: () => T): () => T {
|
||||
}
|
||||
}
|
||||
|
||||
const base64lookupTable = lazyStatic(
|
||||
(): Map<string, number> => {
|
||||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
const ret = new Map<string, number>()
|
||||
for (let i = 0; i < alphabet.length; i++) {
|
||||
ret.set(alphabet.charAt(i), i)
|
||||
}
|
||||
ret.set('=', -1)
|
||||
return ret
|
||||
},
|
||||
)
|
||||
const base64lookupTable = lazyStatic((): Map<string, number> => {
|
||||
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
const ret = new Map<string, number>()
|
||||
for (let i = 0; i < alphabet.length; i++) {
|
||||
ret.set(alphabet.charAt(i), i)
|
||||
}
|
||||
ret.set('=', -1)
|
||||
return ret
|
||||
})
|
||||
|
||||
// NOTE: There are probably simpler solutions to this problem, but I have this written already, so
|
||||
// until we run into problems with this, let's just use this.
|
||||
|
||||
@@ -4,6 +4,8 @@ import {ThemeProvider} from './views/themes/theme'
|
||||
|
||||
console.log(`speedscope v${require('../package.json').version}`)
|
||||
|
||||
/*
|
||||
TODO(jlfwong): Fix this
|
||||
declare const module: any
|
||||
if (module.hot) {
|
||||
module.hot.dispose(() => {
|
||||
@@ -12,6 +14,7 @@ if (module.hot) {
|
||||
})
|
||||
module.hot.accept()
|
||||
}
|
||||
*/
|
||||
|
||||
render(
|
||||
<ThemeProvider>
|
||||
|
||||
@@ -20,10 +20,10 @@ import {Application} from './application'
|
||||
export const ApplicationContainer = memo(() => {
|
||||
const canvas = useAtom(glCanvasAtom)
|
||||
const theme = useTheme()
|
||||
const canvasContext = useMemo(() => (canvas ? getCanvasContext({theme, canvas}) : null), [
|
||||
theme,
|
||||
canvas,
|
||||
])
|
||||
const canvasContext = useMemo(
|
||||
() => (canvas ? getCanvasContext({theme, canvas}) : null),
|
||||
[theme, canvas],
|
||||
)
|
||||
|
||||
return (
|
||||
<ProfileSearchContextProvider>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import '../../assets/reset.css'
|
||||
import '../../assets/source-code-pro.css'
|
||||
|
||||
import {h} from 'preact'
|
||||
import {StyleSheet, css} from 'aphrodite'
|
||||
import {FileSystemDirectoryEntry} from '../import/file-system-entry'
|
||||
|
||||
import {ProfileGroup, SymbolRemapper} from '../lib/profile'
|
||||
import {FontFamily, FontSize, Duration} from './style'
|
||||
import {importEmscriptenSymbolMap as importEmscriptenSymbolRemapper} from '../lib/emscripten'
|
||||
import {SandwichViewContainer} from './sandwich-view'
|
||||
import {saveToFile} from '../lib/file-format'
|
||||
import {ActiveProfileState} from '../app-state/active-profile-state'
|
||||
import {LeftHeavyFlamechartView, ChronoFlamechartView} from './flamechart-view-container'
|
||||
@@ -18,6 +19,7 @@ import {canUseXHR} from '../app-state'
|
||||
import {ProfileGroupState} from '../app-state/profile-group'
|
||||
import {HashParams} from '../lib/hash-params'
|
||||
import {StatelessComponent} from '../lib/preact-helpers'
|
||||
import {SandwichViewContainer} from './sandwich-view'
|
||||
|
||||
const importModule = import('../import')
|
||||
|
||||
@@ -60,6 +62,10 @@ async function importFromFileSystemDirectoryEntry(entry: FileSystemDirectoryEntr
|
||||
declare function require(x: string): any
|
||||
const exampleProfileURL = require('../../sample/profiles/stackcollapse/perf-vertx-stacks-01-collapsed-all.txt')
|
||||
|
||||
function isFileSystemDirectoryEntry(entry: FileSystemEntry): entry is FileSystemDirectoryEntry {
|
||||
return entry != null && entry.isDirectory
|
||||
}
|
||||
|
||||
interface GLCanvasProps {
|
||||
canvasContext: CanvasContext | null
|
||||
theme: Theme
|
||||
@@ -165,6 +171,7 @@ export type ApplicationProps = {
|
||||
|
||||
export class Application extends StatelessComponent<ApplicationProps> {
|
||||
private async loadProfile(loader: () => Promise<ProfileGroup | null>) {
|
||||
this.props.setError(false)
|
||||
this.props.setLoading(true)
|
||||
await new Promise(resolve => setTimeout(resolve, 0))
|
||||
|
||||
@@ -306,13 +313,18 @@ export class Application extends StatelessComponent<ApplicationProps> {
|
||||
|
||||
const firstItem = ev.dataTransfer.items[0]
|
||||
if ('webkitGetAsEntry' in firstItem) {
|
||||
const webkitEntry: FileSystemDirectoryEntry = firstItem.webkitGetAsEntry()
|
||||
const webkitEntry: FileSystemEntry | null = firstItem.webkitGetAsEntry()
|
||||
|
||||
// Instrument.app file format is actually a directory.
|
||||
if (webkitEntry.isDirectory && webkitEntry.name.endsWith('.trace')) {
|
||||
if (
|
||||
webkitEntry &&
|
||||
isFileSystemDirectoryEntry(webkitEntry) &&
|
||||
webkitEntry.name.endsWith('.trace')
|
||||
) {
|
||||
console.log('Importing as Instruments.app .trace file')
|
||||
const webkitDirectoryEntry: FileSystemDirectoryEntry = webkitEntry
|
||||
this.loadProfile(async () => {
|
||||
return await importFromFileSystemDirectoryEntry(webkitEntry)
|
||||
return await importFromFileSystemDirectoryEntry(webkitDirectoryEntry)
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -416,7 +428,7 @@ export class Application extends StatelessComponent<ApplicationProps> {
|
||||
}
|
||||
|
||||
async maybeLoadHashParamProfile() {
|
||||
const {profileURL} = this.props.hashParams;
|
||||
const {profileURL} = this.props.hashParams
|
||||
if (profileURL) {
|
||||
if (!canUseXHR) {
|
||||
alert(
|
||||
|
||||
@@ -308,9 +308,8 @@ export class FlamechartMinimapView extends Component<FlamechartMinimapViewProps,
|
||||
const logicalSpaceMouse = this.windowToLogicalViewSpace().transformPosition(
|
||||
new Vec2(ev.clientX, ev.clientY),
|
||||
)
|
||||
const physicalSpaceMouse = this.logicalToPhysicalViewSpace().transformPosition(
|
||||
logicalSpaceMouse,
|
||||
)
|
||||
const physicalSpaceMouse =
|
||||
this.logicalToPhysicalViewSpace().transformPosition(logicalSpaceMouse)
|
||||
return this.configSpaceToPhysicalViewSpace().inverseTransformPosition(physicalSpaceMouse)
|
||||
}
|
||||
|
||||
|
||||
@@ -239,10 +239,7 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
)
|
||||
|
||||
if (match) {
|
||||
const rangesToHighlightInTrimmedText = remapRangesToTrimmedText(
|
||||
trimmedText,
|
||||
match.matchedRanges,
|
||||
)
|
||||
const rangesToHighlightInTrimmedText = remapRangesToTrimmedText(trimmedText, match)
|
||||
|
||||
// Once we have the character ranges to highlight, we need to
|
||||
// actually do the highlighting.
|
||||
@@ -546,12 +543,10 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
private zoom(logicalViewSpaceCenter: Vec2, multiplier: number) {
|
||||
this.interactionLock = 'zoom'
|
||||
|
||||
const physicalCenter = this.logicalToPhysicalViewSpace().transformPosition(
|
||||
logicalViewSpaceCenter,
|
||||
)
|
||||
const configSpaceCenter = this.configSpaceToPhysicalViewSpace().inverseTransformPosition(
|
||||
physicalCenter,
|
||||
)
|
||||
const physicalCenter =
|
||||
this.logicalToPhysicalViewSpace().transformPosition(logicalViewSpaceCenter)
|
||||
const configSpaceCenter =
|
||||
this.configSpaceToPhysicalViewSpace().inverseTransformPosition(physicalCenter)
|
||||
if (!configSpaceCenter) return
|
||||
|
||||
const zoomTransform = AffineTransform.withTranslation(configSpaceCenter.times(-1))
|
||||
@@ -634,14 +629,12 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
this.onMouseDrag(ev)
|
||||
return
|
||||
}
|
||||
this.hoveredLabel = null
|
||||
|
||||
const logicalViewSpaceMouse = new Vec2(ev.offsetX, ev.offsetY)
|
||||
const physicalViewSpaceMouse = this.logicalToPhysicalViewSpace().transformPosition(
|
||||
logicalViewSpaceMouse,
|
||||
)
|
||||
const configSpaceMouse = this.configSpaceToPhysicalViewSpace().inverseTransformPosition(
|
||||
physicalViewSpaceMouse,
|
||||
)
|
||||
const physicalViewSpaceMouse =
|
||||
this.logicalToPhysicalViewSpace().transformPosition(logicalViewSpaceMouse)
|
||||
const configSpaceMouse =
|
||||
this.configSpaceToPhysicalViewSpace().inverseTransformPosition(physicalViewSpaceMouse)
|
||||
|
||||
if (!configSpaceMouse) return
|
||||
|
||||
@@ -664,6 +657,21 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
|
||||
}
|
||||
}
|
||||
|
||||
// This is a dumb hack to get around what appears to be a bug in
|
||||
// TypeScript's reachability analysis. If I do the this.hoveredLabel = null
|
||||
// in the outer function body, the code below accessing
|
||||
// this.hoveredLabel!.node inside of the `if (this.hoveredLabel) {`
|
||||
// complains that "no property node on never", indicating that it thinks
|
||||
// that codepath is unreachable.
|
||||
//
|
||||
// Because this.hoveredLabel is accessed in the bound function
|
||||
// setHoveredLabel, the codepath is obviously reachable, but the type
|
||||
// checker is confused about this for some reason.
|
||||
const clearHoveredLabel = () => {
|
||||
this.hoveredLabel = null
|
||||
}
|
||||
clearHoveredLabel()
|
||||
|
||||
for (let frame of this.props.flamechart.getLayers()[0] || []) {
|
||||
setHoveredLabel(frame)
|
||||
}
|
||||
|
||||
+36
-30
@@ -3,7 +3,7 @@ import {Sizes, FontSize, FontFamily, ZIndex} from './style'
|
||||
import {css, StyleSheet} from 'aphrodite'
|
||||
import {ComponentChildren, h} from 'preact'
|
||||
import {useTheme, withTheme} from './themes/theme'
|
||||
import { useCallback } from 'preact/hooks'
|
||||
import {useCallback} from 'preact/hooks'
|
||||
|
||||
interface HovertipProps {
|
||||
containerSize: Vec2
|
||||
@@ -20,42 +20,48 @@ export function Hovertip(props: HovertipProps) {
|
||||
|
||||
const OFFSET_FROM_MOUSE = 7
|
||||
|
||||
const updateLocation = useCallback((el: HTMLDivElement | null) => {
|
||||
if (!el) return
|
||||
const updateLocation = useCallback(
|
||||
(el: HTMLDivElement | null) => {
|
||||
if (!el) return
|
||||
|
||||
const clientRect = el.getBoundingClientRect()
|
||||
const clientRect = el.getBoundingClientRect()
|
||||
|
||||
// Place the hovertip to the right of the cursor.
|
||||
let leftEdgeX = offset.x + OFFSET_FROM_MOUSE
|
||||
// Place the hovertip to the right of the cursor.
|
||||
let leftEdgeX = offset.x + OFFSET_FROM_MOUSE
|
||||
|
||||
// If this would cause it to overflow the container, align the right
|
||||
// edge of the hovertip with the right edge of the container.
|
||||
if (leftEdgeX + clientRect.width > containerWidth - 1) {
|
||||
leftEdgeX = containerWidth - clientRect.width - 1
|
||||
// If this would cause it to overflow the container, align the right
|
||||
// edge of the hovertip with the right edge of the container.
|
||||
if (leftEdgeX + clientRect.width > containerWidth - 1) {
|
||||
leftEdgeX = containerWidth - clientRect.width - 1
|
||||
|
||||
// If aligning the right edge overflows the container, align the left edge
|
||||
// of the hovertip with the left edge of the container.
|
||||
if (leftEdgeX < 1) { leftEdgeX = 1 }
|
||||
}
|
||||
el.style.left = `${leftEdgeX}px`
|
||||
// If aligning the right edge overflows the container, align the left edge
|
||||
// of the hovertip with the left edge of the container.
|
||||
if (leftEdgeX < 1) {
|
||||
leftEdgeX = 1
|
||||
}
|
||||
}
|
||||
el.style.left = `${leftEdgeX}px`
|
||||
|
||||
// Place the tooltip below the cursor
|
||||
let topEdgeY = offset.y + OFFSET_FROM_MOUSE
|
||||
// Place the tooltip below the cursor
|
||||
let topEdgeY = offset.y + OFFSET_FROM_MOUSE
|
||||
|
||||
// If this would cause it to overflow the container, place the hovertip
|
||||
// above the cursor instead. This intentionally differs from the horizontal
|
||||
// axis logic to avoid the cursor being in the middle of a hovertip when
|
||||
// possible.
|
||||
if (topEdgeY + clientRect.height > containerHeight - 1) {
|
||||
topEdgeY = offset.y - clientRect.height - 1
|
||||
// If this would cause it to overflow the container, place the hovertip
|
||||
// above the cursor instead. This intentionally differs from the horizontal
|
||||
// axis logic to avoid the cursor being in the middle of a hovertip when
|
||||
// possible.
|
||||
if (topEdgeY + clientRect.height > containerHeight - 1) {
|
||||
topEdgeY = offset.y - clientRect.height - 1
|
||||
|
||||
// If placing the hovertip above the cursor overflows the container, align
|
||||
// the top edge of the hovertip with the top edge of the container.
|
||||
if (topEdgeY < 1) { topEdgeY = 1 }
|
||||
}
|
||||
el.style.top = `${topEdgeY}px`
|
||||
|
||||
}, [containerWidth, containerHeight, offset.x, offset.y])
|
||||
// If placing the hovertip above the cursor overflows the container, align
|
||||
// the top edge of the hovertip with the top edge of the container.
|
||||
if (topEdgeY < 1) {
|
||||
topEdgeY = 1
|
||||
}
|
||||
}
|
||||
el.style.top = `${topEdgeY}px`
|
||||
},
|
||||
[containerWidth, containerHeight, offset.x, offset.y],
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={css(style.hoverTip)} ref={updateLocation}>
|
||||
|
||||
@@ -217,7 +217,7 @@ export const ProfileTableView = memo(
|
||||
rows.push(
|
||||
ProfileTableRowView({
|
||||
frame,
|
||||
matchedRanges: match == null ? null : match.matchedRanges,
|
||||
matchedRanges: match == null ? null : match,
|
||||
index: i,
|
||||
profile: profile,
|
||||
selectedFrame: selectedFrame,
|
||||
@@ -268,12 +268,14 @@ export const ProfileTableView = memo(
|
||||
[sandwichContext],
|
||||
)
|
||||
|
||||
const onTotalClick = useCallback((ev: MouseEvent) => onSortClick(SortField.TOTAL, ev), [
|
||||
onSortClick,
|
||||
])
|
||||
const onSelfClick = useCallback((ev: MouseEvent) => onSortClick(SortField.SELF, ev), [
|
||||
onSortClick,
|
||||
])
|
||||
const onTotalClick = useCallback(
|
||||
(ev: MouseEvent) => onSortClick(SortField.TOTAL, ev),
|
||||
[onSortClick],
|
||||
)
|
||||
const onSelfClick = useCallback(
|
||||
(ev: MouseEvent) => onSortClick(SortField.SELF, ev),
|
||||
[onSortClick],
|
||||
)
|
||||
const onSymbolNameClick = useCallback(
|
||||
(ev: MouseEvent) => onSortClick(SortField.SYMBOL_NAME, ev),
|
||||
[onSortClick],
|
||||
|
||||
@@ -11,7 +11,6 @@ import {SandwichSearchView} from './sandwich-search-view'
|
||||
import {ActiveProfileState} from '../app-state/active-profile-state'
|
||||
import {sortBy} from '../lib/utils'
|
||||
import {ProfileSearchContext} from './search-view'
|
||||
import {FuzzyMatch} from '../lib/fuzzy-find'
|
||||
import {Theme, useTheme, withTheme} from './themes/theme'
|
||||
import {SortField, SortDirection, profileGroupAtom, tableSortMethodAtom} from '../app-state'
|
||||
import {useAtom} from '../lib/atom'
|
||||
@@ -141,7 +140,7 @@ interface SandwichViewContextData {
|
||||
selectedFrame: Frame | null
|
||||
setSelectedFrame: (frame: Frame | null) => void
|
||||
getIndexForFrame: (frame: Frame) => number | null
|
||||
getSearchMatchForFrame: (frame: Frame) => FuzzyMatch | null
|
||||
getSearchMatchForFrame: (frame: Frame) => [number, number][] | null
|
||||
}
|
||||
|
||||
export const SandwichViewContext = createContext<SandwichViewContextData | null>(null)
|
||||
@@ -204,7 +203,7 @@ export const SandwichViewContainer = memo((ownProps: SandwichViewContainerProps)
|
||||
}
|
||||
}, [rowList])
|
||||
|
||||
const getSearchMatchForFrame: (frame: Frame) => FuzzyMatch | null = useMemo(() => {
|
||||
const getSearchMatchForFrame: (frame: Frame) => [number, number][] | null = useMemo(() => {
|
||||
return (frame: Frame) => {
|
||||
if (profileSearchResults == null) return null
|
||||
return profileSearchResults.getMatchForFrame(frame)
|
||||
|
||||
Reference in New Issue
Block a user