Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a4f38a8cb | ||
|
|
9361a6baf2 | ||
|
|
ede9c74d50 | ||
|
|
f758130455 | ||
|
|
f3a1c09c9b | ||
|
|
069c0194a6 |
@@ -0,0 +1,43 @@
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x, 12.x, 14.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
- run: npm test
|
||||
env:
|
||||
CI: true
|
||||
|
||||
- name: Coveralls Parallel
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
flag-name: run-${{ matrix.node-version }}
|
||||
parallel: true
|
||||
|
||||
finish:
|
||||
needs: test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Coveralls Finished
|
||||
uses: coverallsapp/github-action@master
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
parallel-finished: true
|
||||
@@ -1,6 +0,0 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- '10'
|
||||
- '12'
|
||||
- '13'
|
||||
- 'node'
|
||||
@@ -1,5 +1,17 @@
|
||||
## Unreleased
|
||||
|
||||
## [1.10.0] - 2020-09-29
|
||||
|
||||
### Added
|
||||
|
||||
- Support for importing profiles from Safari [[#300](https://github.com/jlfwong/speedscope/pull/300)] (by [@radex](https://github.com/radex))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed browser not opening on Windows when using the CLI [[#307](https://github.com/jlfwong/speedscope/pull/307)] (by [@spillerrec](https://github.com/spillerrec))
|
||||
- Fixed import of UTF-16 encoded files w/ BOM [[#314](https://github.com/jlfwong/speedscope/pull/314)]
|
||||
- Removed accidental dependency on React [[#315](https://github.com/jlfwong/speedscope/pull/315)]
|
||||
|
||||
## [1.9.0] - 2020-08-05
|
||||
|
||||
### Added
|
||||
|
||||
@@ -36,6 +36,7 @@ speedscope is designed to ingest profiles from a variety of different profilers
|
||||
- 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))
|
||||
|
||||
+6
-2
@@ -4,7 +4,7 @@ const fs = require('fs')
|
||||
const os = require('os')
|
||||
const stream = require('stream')
|
||||
|
||||
const opn = require('opn')
|
||||
const open = require('open')
|
||||
|
||||
const helpString = `Usage: speedscope [filepath]
|
||||
|
||||
@@ -89,7 +89,11 @@ async function main() {
|
||||
|
||||
console.log('Opening', urlToOpen, 'in your default browser')
|
||||
|
||||
await opn(urlToOpen, {wait: false})
|
||||
// We'd like to avoid blocking the terminal on the browsing closing,
|
||||
// but for some reason this doesn't work at all on Windows if we
|
||||
// don't use wait: true.
|
||||
const wait = process.platform === "win32";
|
||||
await open(urlToOpen, {wait})
|
||||
}
|
||||
|
||||
main()
|
||||
|
||||
Generated
+35
-101
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.5.3",
|
||||
"version": "1.9.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -3423,27 +3423,6 @@
|
||||
"parse-json": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"coveralls": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.0.1.tgz",
|
||||
"integrity": "sha512-FAzXwiDOYLGDWH+zgoIA+8GbWv50hlx+kpEJyvzLKOdnIBv9uWoVl4DhqGgyUHpiRjAlF8KYZSipWXYtllWH6Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"js-yaml": "^3.6.1",
|
||||
"lcov-parse": "^0.0.10",
|
||||
"log-driver": "^1.2.5",
|
||||
"minimist": "^1.2.0",
|
||||
"request": "^2.79.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"create-ecdh": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz",
|
||||
@@ -5793,15 +5772,6 @@
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"react-is": "^16.7.0"
|
||||
}
|
||||
},
|
||||
"hosted-git-info": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz",
|
||||
@@ -6249,6 +6219,11 @@
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
|
||||
"dev": true
|
||||
},
|
||||
"is-docker": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
|
||||
"integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw=="
|
||||
},
|
||||
"is-extendable": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
|
||||
@@ -6397,7 +6372,8 @@
|
||||
"is-wsl": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
|
||||
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
|
||||
"integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
|
||||
"dev": true
|
||||
},
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
@@ -7076,7 +7052,8 @@
|
||||
"js-tokens": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
|
||||
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
|
||||
"dev": true
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.13.1",
|
||||
@@ -7283,12 +7260,6 @@
|
||||
"integrity": "sha1-iAy4qrJWAmOC4C9T7AiWgqdMW2o=",
|
||||
"dev": true
|
||||
},
|
||||
"lcov-parse": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz",
|
||||
"integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=",
|
||||
"dev": true
|
||||
},
|
||||
"left-pad": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
|
||||
@@ -7395,12 +7366,6 @@
|
||||
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
|
||||
"dev": true
|
||||
},
|
||||
"log-driver": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
|
||||
"integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==",
|
||||
"dev": true
|
||||
},
|
||||
"log-symbols": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz",
|
||||
@@ -7420,6 +7385,7 @@
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
|
||||
"integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0"
|
||||
}
|
||||
@@ -7885,7 +7851,8 @@
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"dev": true
|
||||
},
|
||||
"object-copy": {
|
||||
"version": "0.1.0",
|
||||
@@ -8139,10 +8106,30 @@
|
||||
"mimic-fn": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"open": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/open/-/open-7.2.0.tgz",
|
||||
"integrity": "sha512-4HeyhxCvBTI5uBePsAdi55C5fmqnWZ2e2MlmvWi5KW5tdH5rxoiv/aMtbeVxKZc3eWkT1GymMnLG8XC4Rq4TDQ==",
|
||||
"requires": {
|
||||
"is-docker": "^2.0.0",
|
||||
"is-wsl": "^2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
|
||||
"integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
|
||||
"requires": {
|
||||
"is-docker": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"opn": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz",
|
||||
"integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-wsl": "^1.1.0"
|
||||
}
|
||||
@@ -9244,26 +9231,6 @@
|
||||
"sisteransi": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"prop-types": {
|
||||
"version": "15.7.2",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
|
||||
"integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"react-is": "^16.8.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"protobufjs": {
|
||||
"version": "6.8.8",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz",
|
||||
@@ -9512,44 +9479,11 @@
|
||||
"integrity": "sha1-CMbgSgFo9utiHCKrbLEVG9n0pk0=",
|
||||
"dev": true
|
||||
},
|
||||
"react": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
"prop-types": "^15.6.2"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.12.0",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz",
|
||||
"integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q=="
|
||||
},
|
||||
"react-redux": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz",
|
||||
"integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"hoist-non-react-statics": "^3.3.0",
|
||||
"loose-envify": "^1.4.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react-is": "^16.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
"integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==",
|
||||
"dev": true
|
||||
},
|
||||
"read-pkg": {
|
||||
"version": "3.0.0",
|
||||
|
||||
+3
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "speedscope",
|
||||
"version": "1.9.0",
|
||||
"version": "1.10.0",
|
||||
"description": "",
|
||||
"repository": "jlfwong/speedscope",
|
||||
"main": "index.js",
|
||||
@@ -13,7 +13,7 @@
|
||||
"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 && coveralls < coverage/lcov.info",
|
||||
"coverage": "npm run jest -- --coverage",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "./scripts/ci.sh",
|
||||
"serve": "parcel assets/index.html --open --no-autoinstall"
|
||||
@@ -38,7 +38,6 @@
|
||||
"@typescript-eslint/parser": "2.33.0",
|
||||
"acorn": "7.2.0",
|
||||
"aphrodite": "2.1.0",
|
||||
"coveralls": "3.0.1",
|
||||
"eslint": "6.0.0",
|
||||
"eslint-plugin-prettier": "2.6.0",
|
||||
"eslint-plugin-react-hooks": "4.0.2",
|
||||
@@ -50,7 +49,6 @@
|
||||
"preact": "10.4.1",
|
||||
"prettier": "2.0.4",
|
||||
"protobufjs": "6.8.8",
|
||||
"react-redux": "^7.2.0",
|
||||
"redux": "^4.0.5",
|
||||
"ts-jest": "24.3.0",
|
||||
"typescript": "3.9.2",
|
||||
@@ -79,7 +77,6 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"opn": "5.3.0",
|
||||
"react": "^16.13.1"
|
||||
"open": "7.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -104,6 +104,114 @@ exports[`importFromBGFlameGraph with CRLF: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromBGFlameGraph with CRLF: profileGroup.name 1`] = `"simple-crlf.txt"`;
|
||||
|
||||
exports[`importFromBGFlameGraph with UTF-16, Big Endian 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "a",
|
||||
"line": undefined,
|
||||
"name": "a",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "b",
|
||||
"line": undefined,
|
||||
"name": "b",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "c",
|
||||
"line": undefined,
|
||||
"name": "c",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "d",
|
||||
"line": undefined,
|
||||
"name": "d",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "simple-utf16-be.txt",
|
||||
"stacks": Array [
|
||||
"a;b;c 2",
|
||||
"a;b;d 4",
|
||||
"a;b;c 3",
|
||||
"a;b 5",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromBGFlameGraph with UTF-16, Big Endian: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromBGFlameGraph with UTF-16, Big Endian: profileGroup.name 1`] = `"simple-utf16-be.txt"`;
|
||||
|
||||
exports[`importFromBGFlameGraph with UTF-16, Little Endian 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "a",
|
||||
"line": undefined,
|
||||
"name": "a",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "b",
|
||||
"line": undefined,
|
||||
"name": "b",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 14,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "c",
|
||||
"line": undefined,
|
||||
"name": "c",
|
||||
"selfWeight": 5,
|
||||
"totalWeight": 5,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": "d",
|
||||
"line": undefined,
|
||||
"name": "d",
|
||||
"selfWeight": 4,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
],
|
||||
"name": "simple-utf16-le.txt",
|
||||
"stacks": Array [
|
||||
"a;b;c 2",
|
||||
"a;b;d 4",
|
||||
"a;b;c 3",
|
||||
"a;b 5",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromBGFlameGraph with UTF-16, Little Endian: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromBGFlameGraph with UTF-16, Little Endian: profileGroup.name 1`] = `"simple-utf16-le.txt"`;
|
||||
|
||||
exports[`importFromBGFlameGraph: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromBGFlameGraph: profileGroup.name 1`] = `"simple.txt"`;
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importFromSafari 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": 13,
|
||||
"file": "__InjectedScript_InjectedScriptSource.js",
|
||||
"key": "injectModule:__InjectedScript_InjectedScriptSource.js:109:13",
|
||||
"line": 109,
|
||||
"name": "injectModule",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0.001,
|
||||
},
|
||||
Frame {
|
||||
"col": 10,
|
||||
"file": "__InjectedScript_CommandLineAPIModuleSource.js",
|
||||
"key": ":__InjectedScript_CommandLineAPIModuleSource.js:2:10",
|
||||
"line": 2,
|
||||
"name": "(anonymous)",
|
||||
"selfWeight": 0.001,
|
||||
"totalWeight": 0.001,
|
||||
},
|
||||
Frame {
|
||||
"col": 1,
|
||||
"file": "file:///speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "(program):file:///speedscope/sample/programs/javascript/simple.js:1:1",
|
||||
"line": 1,
|
||||
"name": "(program)",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0.03248933597933502,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "file:///speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "alpha:file:///speedscope/sample/programs/javascript/simple.js:1:15",
|
||||
"line": 1,
|
||||
"name": "alpha",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0.03248933597933502,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "file:///speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "delta:file:///speedscope/sample/programs/javascript/simple.js:14:15",
|
||||
"line": 14,
|
||||
"name": "delta",
|
||||
"selfWeight": 0.003094222474222382,
|
||||
"totalWeight": 0.020112446082445484,
|
||||
},
|
||||
Frame {
|
||||
"col": 15,
|
||||
"file": "file:///speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "gamma:file:///speedscope/sample/programs/javascript/simple.js:20:15",
|
||||
"line": 20,
|
||||
"name": "gamma",
|
||||
"selfWeight": 0.029395113505112636,
|
||||
"totalWeight": 0.029395113505112636,
|
||||
},
|
||||
Frame {
|
||||
"col": 14,
|
||||
"file": "file:///speedscope/sample/programs/javascript/simple.js",
|
||||
"key": "beta:file:///speedscope/sample/programs/javascript/simple.js:8:14",
|
||||
"line": 8,
|
||||
"name": "beta",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0.012376889896889526,
|
||||
},
|
||||
Frame {
|
||||
"col": 102,
|
||||
"file": "",
|
||||
"key": "firstOpenSearchURLString::4:102",
|
||||
"line": 4,
|
||||
"name": "firstOpenSearchURLString",
|
||||
"selfWeight": 0.0005174240213818848,
|
||||
"totalWeight": 0.0005174240213818848,
|
||||
},
|
||||
],
|
||||
"name": "Grabación de Control temporal 1",
|
||||
"stacks": Array [
|
||||
"injectModule;(anonymous) 1.00ms",
|
||||
" 39.93ms",
|
||||
"(program);alpha;delta;gamma 10.83ms",
|
||||
" 2.46ms",
|
||||
"(program);alpha;delta 3.09ms",
|
||||
"(program);alpha;beta;gamma 4.64ms",
|
||||
"(program);alpha;delta;gamma 1.55ms",
|
||||
"(program);alpha;beta;gamma 1.55ms",
|
||||
"(program);alpha;delta;gamma 3.09ms",
|
||||
"(program);alpha;beta;gamma 4.64ms",
|
||||
"(program);alpha;delta;gamma 1.55ms",
|
||||
"(program);alpha;beta;gamma 1.55ms",
|
||||
" 253.50ms",
|
||||
"firstOpenSearchURLString 517.42µs",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromSafari: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromSafari: profileGroup.name 1`] = `"Grabación de Control temporal 1"`;
|
||||
@@ -7,3 +7,11 @@ test('importFromBGFlameGraph', async () => {
|
||||
test('importFromBGFlameGraph with CRLF', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackcollapse/simple-crlf.txt')
|
||||
})
|
||||
|
||||
test('importFromBGFlameGraph with UTF-16, Little Endian', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackcollapse/simple-utf16-le.txt')
|
||||
})
|
||||
|
||||
test('importFromBGFlameGraph with UTF-16, Big Endian', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/stackcollapse/simple-utf16-be.txt')
|
||||
})
|
||||
|
||||
@@ -15,6 +15,7 @@ import {importSpeedscopeProfiles} from '../lib/file-format'
|
||||
import {importFromV8ProfLog} from './v8proflog'
|
||||
import {importFromLinuxPerf} from './linux-tools-perf'
|
||||
import {importFromHaskell} from './haskell'
|
||||
import {importFromSafari} from './safari'
|
||||
import {ProfileDataSource, TextProfileDataSource, MaybeCompressedDataReader} from './utils'
|
||||
import {importAsPprofProfile} from './pprof'
|
||||
import {decodeBase64} from '../lib/utils'
|
||||
@@ -131,6 +132,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
} else if (fileName.endsWith('.heapprofile')) {
|
||||
console.log('Importing as Chrome Heap Profile')
|
||||
return toGroup(importFromChromeHeapProfile(JSON.parse(contents)))
|
||||
} else if (fileName.endsWith('-recording.json')) {
|
||||
console.log('Importing as Safari profile')
|
||||
return toGroup(importFromSafari(JSON.parse(contents)))
|
||||
}
|
||||
|
||||
// Second pass: Try to guess what file format it is based on structure
|
||||
@@ -169,6 +173,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
} else if ('rts_arguments' in parsed && 'initial_capabilities' in parsed) {
|
||||
console.log('Importing as Haskell GHC JSON Profile')
|
||||
return importFromHaskell(parsed)
|
||||
} else if ('recording' in parsed && 'sampleStackTraces' in parsed.recording) {
|
||||
console.log('Importing as Safari profile')
|
||||
return toGroup(importFromSafari(JSON.parse(contents)))
|
||||
}
|
||||
} else {
|
||||
// Format is not JSON
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import {checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
test('importFromSafari', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/Safari/13.1/simple.html-recording.json')
|
||||
})
|
||||
@@ -0,0 +1,120 @@
|
||||
import {Profile, FrameInfo, StackListProfileBuilder} from '../lib/profile'
|
||||
import {TimeFormatter} from '../lib/value-formatters'
|
||||
|
||||
interface Record {
|
||||
type: string
|
||||
eventType?: string
|
||||
startTime?: number
|
||||
endTime?: number
|
||||
// timeline-record-type-cpu
|
||||
timestamp?: number
|
||||
usage?: number
|
||||
threads?: any[]
|
||||
// timeline-record-type-script
|
||||
details?: number | string | any
|
||||
extraDetails?: null | any
|
||||
// timeline-record-type-network
|
||||
archiveStartTime?: number
|
||||
entry?: any
|
||||
// timeline-record-type-layout
|
||||
quad?: number[]
|
||||
}
|
||||
|
||||
interface ExprLocation {
|
||||
line: number
|
||||
column: number
|
||||
}
|
||||
|
||||
interface StackFrame {
|
||||
sourceID: string
|
||||
name: string
|
||||
line: number
|
||||
column: number
|
||||
url: string
|
||||
expressionLocation?: ExprLocation
|
||||
}
|
||||
|
||||
interface Sample {
|
||||
timestamp: number
|
||||
stackFrames: StackFrame[]
|
||||
}
|
||||
|
||||
interface Recording {
|
||||
displayName: string
|
||||
startTime: number
|
||||
endTime: number
|
||||
discontinuities: any[]
|
||||
instrumentTypes: string[]
|
||||
records: Record[]
|
||||
markers: any[]
|
||||
memoryPressureEvents: any[]
|
||||
sampleStackTraces: Sample[]
|
||||
sampleDurations: number[]
|
||||
}
|
||||
|
||||
interface Overview {
|
||||
secondsPerPixel: number
|
||||
scrollStartTime: number
|
||||
selectionStartTime: number
|
||||
selectionDuration: number
|
||||
}
|
||||
|
||||
interface SafariProfile {
|
||||
version: number
|
||||
recording: Recording
|
||||
overview: Overview
|
||||
}
|
||||
|
||||
function makeStack(frames: StackFrame[]): FrameInfo[] {
|
||||
return frames
|
||||
.map(({name, url, line, column}) => ({
|
||||
key: `${name}:${url}:${line}:${column}`,
|
||||
file: url,
|
||||
line,
|
||||
col: column,
|
||||
name: name || '(anonymous)',
|
||||
}))
|
||||
.reverse()
|
||||
}
|
||||
|
||||
export function importFromSafari(contents: SafariProfile): Profile | null {
|
||||
if (contents.version !== 1) {
|
||||
console.warn(`Unknown Safari profile version ${contents.version}... Might be incompatible.`)
|
||||
}
|
||||
|
||||
const {recording} = contents
|
||||
const {sampleStackTraces, sampleDurations} = recording
|
||||
|
||||
const count = sampleStackTraces.length
|
||||
if (count < 1) {
|
||||
console.warn('Empty profile')
|
||||
return null
|
||||
}
|
||||
|
||||
const profileDuration =
|
||||
sampleStackTraces[count - 1].timestamp - sampleStackTraces[0].timestamp + sampleDurations[0]
|
||||
const profile = new StackListProfileBuilder(profileDuration)
|
||||
|
||||
let previousEndTime = Number.MAX_VALUE
|
||||
|
||||
sampleStackTraces.forEach((sample, i) => {
|
||||
const endTime = sample.timestamp
|
||||
const duration = sampleDurations[i]
|
||||
const startTime = endTime - duration
|
||||
const idleDurationBefore = startTime - previousEndTime
|
||||
|
||||
// FIXME: 2ms is a lot, but Safari's timestamps and durations don't line up very well and will create
|
||||
// phantom idle time
|
||||
if (idleDurationBefore > 0.002) {
|
||||
profile.appendSampleWithWeight([], idleDurationBefore)
|
||||
}
|
||||
|
||||
profile.appendSampleWithWeight(makeStack(sample.stackFrames), duration)
|
||||
|
||||
previousEndTime = endTime
|
||||
})
|
||||
|
||||
profile.setValueFormatter(new TimeFormatter('seconds'))
|
||||
profile.setName(recording.displayName)
|
||||
return profile.build()
|
||||
}
|
||||
+20
-5
@@ -51,15 +51,30 @@ export class MaybeCompressedDataReader implements ProfileDataSource {
|
||||
|
||||
async readAsText(): Promise<string> {
|
||||
const buffer = await this.readAsArrayBuffer()
|
||||
let ret: string = ''
|
||||
|
||||
// By default, we assume the file is utf-8 encoded.
|
||||
let encoding = 'utf-8'
|
||||
|
||||
const array = new Uint8Array(buffer)
|
||||
if (array.length > 2) {
|
||||
if (array[0] === 0xff && array[1] === 0xfe) {
|
||||
// UTF-16, Little Endian encoding
|
||||
encoding = 'utf-16le'
|
||||
} else if (array[0] === 0xfe && array[1] === 0xff) {
|
||||
// UTF-16, Big Endian encoding
|
||||
encoding = 'utf-16be'
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') {
|
||||
const decoder = new TextDecoder()
|
||||
const decoder = new TextDecoder(encoding)
|
||||
return decoder.decode(buffer)
|
||||
} else {
|
||||
// JavaScript strings are UTF-16 encoded, but we're reading data
|
||||
// from disk that we're going to asusme is UTF-8 encoded.
|
||||
const array = new Uint8Array(buffer)
|
||||
// JavaScript strings are UTF-16 encoded, but we're reading data from disk
|
||||
// that we're going to blindly assume it's ASCII encoded. This codepath
|
||||
// only exists for older browser support.
|
||||
console.warn('This browser does not support TextDecoder. Decoding text as ASCII.')
|
||||
let ret: string = ''
|
||||
for (let i = 0; i < array.length; i++) {
|
||||
ret += String.fromCharCode(array[i])
|
||||
}
|
||||
|
||||
+8
-2
@@ -16,7 +16,7 @@
|
||||
// Because we're not going to use this in our actual build, it's okay for this
|
||||
// to be inefficient.
|
||||
|
||||
(function () {
|
||||
;(function () {
|
||||
const nodeVersion = process.versions.node
|
||||
const versionParts = nodeVersion.split('.')
|
||||
const majorVersion = parseInt(versionParts[0], 10)
|
||||
@@ -48,4 +48,10 @@
|
||||
this.splice(0, this.length, ...arrayWithIndices.map(x => x[0]))
|
||||
return this
|
||||
}
|
||||
})()
|
||||
})()
|
||||
;(function () {
|
||||
// TextDecoder is a global API in browsers, but an imported API in node.
|
||||
//
|
||||
// Let's emulate it being a global API during tests.
|
||||
global.TextDecoder = require('util').TextDecoder
|
||||
})()
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* As of Preact 10.x, they no longer have an officially supported preact-redux library.
|
||||
* It's possible to use react-redux with some hacks, but these hacks cause npm run pack
|
||||
* to error out because of (intentinoally) unmet peer dependencies.
|
||||
* to error out because of (intentionally) unmet peer dependencies.
|
||||
*
|
||||
* I could stack more hacks to fix this problem, but I'd rather just drop the dependency
|
||||
* and remove the need to do any dependency hacking by writing the very small part of
|
||||
|
||||
Reference in New Issue
Block a user