Fix the build for node 13.x, make travis test 10, 12, 13, stable (#263)

@JustinBeckwith pointed out in #262 that `npm install` was broken in node 13.x, and @DanielRuf pointed in #254 that test fail for node 11+ because of a change to stability of sorting.

This PR seeks to address both of those.

The installation issue was fixed by just regenerating `package-lock.json` without needing to bump any of the direct dependency versions. The test failure issue requires manual intervention.

To fix the sort stability issue, I updated the tests to use the stable sort values (these were all the correct values, though some of the test values were incorrect).

To make the suite still pass for node 10, I added a hack where I override `Array.prototype.sort` with a stable implementation that's *only* used in tests (See comments in code for a justification for why)

## Test Plan

Before this PR: `npm install` on node 13.x fails & `npm run jest` results in test failures
After this PR: `npm install` on node 13.x passes & `npm run jest` passes for node 10, 12, and 13.
This commit is contained in:
Jamie Wong 2020-04-20 08:26:59 -07:00 committed by GitHub
parent fd4195da10
commit d30bb2ef7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 368 additions and 913 deletions

View File

@ -1,3 +1,6 @@
language: node_js language: node_js
node_js: node_js:
- '9' - '10'
- '12'
- '13'
- 'node'

658
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "speedscope", "name": "speedscope",
"version": "1.5.2", "version": "1.5.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -2458,10 +2458,13 @@
"dev": true "dev": true
}, },
"bindings": { "bindings": {
"version": "1.2.1", "version": "1.5.0",
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true "dev": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
}, },
"bluebird": { "bluebird": {
"version": "3.5.1", "version": "3.5.1",
@ -2861,620 +2864,6 @@
"upath": "^1.0.5" "upath": "^1.0.5"
}, },
"dependencies": { "dependencies": {
"fsevents": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
"integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
"dev": true,
"optional": true,
"requires": {
"nan": "^2.9.2",
"node-pre-gyp": "^0.10.0"
},
"dependencies": {
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"dev": true,
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true,
"optional": true
},
"are-we-there-yet": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
"integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
"dev": true,
"optional": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"chownr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz",
"integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=",
"dev": true,
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"dev": true,
"optional": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"requires": {
"ms": "2.0.0"
}
},
"deep-extend": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.5.1.tgz",
"integrity": "sha512-N8vBdOa+DF7zkRrDCsaOXoCs/E2fJfx9B9MrKnnSiHNh4ws7eSys6YQE4KvT1cecKmOASYQBhbKjeuDD9lT81w==",
"dev": true,
"optional": true
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true,
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"dev": true,
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"dev": true,
"optional": true
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"optional": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"dev": true,
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true,
"optional": true
},
"iconv-lite": {
"version": "0.4.21",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.21.tgz",
"integrity": "sha512-En5V9za5mBt2oUA03WGD3TwDv0MKAruqsuxstbMUZaj9W9k/m1CV/9py3l0L5kw9Bln8fdHQmzHSYtvpvTLpKw==",
"dev": true,
"optional": true,
"requires": {
"safer-buffer": "^2.1.0"
}
},
"ignore-walk": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
"requires": {
"minimatch": "^3.0.4"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"dev": true,
"optional": true,
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true,
"optional": true
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz",
"integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==",
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
}
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true,
"optional": true
},
"needle": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz",
"integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==",
"dev": true,
"optional": true,
"requires": {
"debug": "^2.1.2",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
}
},
"node-pre-gyp": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.0.tgz",
"integrity": "sha512-G7kEonQLRbcA/mOoFoxvlMrw6Q6dPf92+t/l0DFSMuSlDoWaI9JWIyPwK0jyE1bph//CUEL65/Fz1m2vJbmjQQ==",
"dev": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.0",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.1.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
}
},
"nopt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
},
"npm-bundled": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.3.tgz",
"integrity": "sha512-ByQ3oJ/5ETLyglU2+8dBObvhfWXX8dtPZDMePCahptliFX2iIuhyEszyFk401PZUNQH20vvdW5MLjJxkwU80Ow==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.10",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.10.tgz",
"integrity": "sha512-AQC0Dyhzn4EiYEfIUjCdMl0JJ61I2ER9ukf/sLxJUcZHfo+VyEfz2rMJgLZSS1v30OxPQe1cN0LZA1xbcaVfWA==",
"dev": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1"
}
},
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"dev": true,
"optional": true
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"dev": true,
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"dev": true,
"optional": true
},
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"dev": true,
"optional": true,
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"dev": true,
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"dev": true,
"optional": true
},
"rc": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.7.tgz",
"integrity": "sha512-LdLD8xD4zzLsAT5xyushXDNscEjB7+2ulnl8+r1pnESlYtlJtVSoCMBGr30eDRJ3+2Gq89jK9P9e4tCEH1+ywA==",
"dev": true,
"optional": true,
"requires": {
"deep-extend": "^0.5.1",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true,
"optional": true
}
}
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"optional": true,
"requires": {
"glob": "^7.0.5"
}
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"dev": true,
"optional": true
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
"dev": true,
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"dev": true,
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true,
"optional": true
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true,
"optional": true
},
"tar": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.1.tgz",
"integrity": "sha512-O+v1r9yN4tOsvl90p5HAP4AEqbYhx4036AGMm075fH9F8Qwi3oJ+v4u50FkT/KkvywNGtwkk0zRI+8eYm1X/xg==",
"dev": true,
"optional": true,
"requires": {
"chownr": "^1.0.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.2.4",
"minizlib": "^1.1.0",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.1",
"yallist": "^3.0.2"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"dev": true,
"optional": true
},
"wide-align": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
"integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
"dev": true,
"optional": true,
"requires": {
"string-width": "^1.0.2"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true,
"optional": true
}
}
},
"glob-parent": { "glob-parent": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
@ -4328,13 +3717,13 @@
"dev": true "dev": true
}, },
"deasync": { "deasync": {
"version": "0.1.13", "version": "0.1.19",
"resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.13.tgz", "resolved": "https://registry.npmjs.org/deasync/-/deasync-0.1.19.tgz",
"integrity": "sha512-/6ngYM7AapueqLtvOzjv9+11N2fHDSrkxeMF1YPE20WIfaaawiBg+HZH1E5lHrcJxlKR42t6XPOEmMmqcAsU1g==", "integrity": "sha512-oh3MRktfnPlLysCPpBpKZZzb4cUC/p0aA3SyRGp15lN30juJBTo/CiD0d4fR+f1kBtUQoJj1NE9RPNWQ7BQ9Mg==",
"dev": true, "dev": true,
"requires": { "requires": {
"bindings": "~1.2.1", "bindings": "^1.5.0",
"nan": "^2.0.7" "node-addon-api": "^1.7.1"
} }
}, },
"debug": { "debug": {
@ -5205,8 +4594,7 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true, "dev": true
"optional": true
}, },
"filesize": { "filesize": {
"version": "3.6.1", "version": "3.6.1",
@ -8136,12 +7524,6 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
"dev": true "dev": true
}, },
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
"dev": true
},
"nanomatch": { "nanomatch": {
"version": "1.2.9", "version": "1.2.9",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz",
@ -8194,6 +7576,12 @@
"integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==",
"dev": true "dev": true
}, },
"node-addon-api": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.1.tgz",
"integrity": "sha512-2+DuKodWvwRTrCfKOeR24KIc5unKjOh8mz17NCzVnHWfjAdDqbfbjqh7gUT+BkXBRQM52+xCHciKWonJ3CbJMQ==",
"dev": true
},
"node-fetch": { "node-fetch": {
"version": "1.7.3", "version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
@ -10955,9 +10343,9 @@
"dev": true "dev": true
}, },
"prettier": { "prettier": {
"version": "1.12.0", "version": "2.0.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.0.tgz", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.4.tgz",
"integrity": "sha512-Wz0SMncgaglBzDcohH3ZIAi4nVpzOIEweFzCOmgVEoRSeO72b4dcKGfgxoRGVMaFlh1r7dlVaJ+f3CIHfeH6xg==", "integrity": "sha512-SVJIQ51spzFDvh4fIbCLvciiDMCrRhlN3mbZvv/+ycjvmF5E73bKdGfU8QDLNmjYJf+lsGnDBC4UUnvTe5OO0w==",
"dev": true "dev": true
}, },
"pretty-format": { "pretty-format": {

View File

@ -44,7 +44,7 @@
"parcel-bundler": "1.9.2", "parcel-bundler": "1.9.2",
"preact": "8.2.7", "preact": "8.2.7",
"preact-redux": "jlfwong/preact-redux#a56dcc4", "preact-redux": "jlfwong/preact-redux#a56dcc4",
"prettier": "1.12.0", "prettier": "2.0.4",
"protobufjs": "6.8.8", "protobufjs": "6.8.8",
"quicktype": "15.0.209", "quicktype": "15.0.209",
"redux": "^4.0.0", "redux": "^4.0.0",
@ -57,6 +57,9 @@
"transform": { "transform": {
"^.+\\.tsx?$": "ts-jest" "^.+\\.tsx?$": "ts-jest"
}, },
"setupFilesAfterEnv": [
"./src/jest-setup.js"
],
"testRegex": "\\.test\\.tsx?$", "testRegex": "\\.test\\.tsx?$",
"collectCoverageFrom": [ "collectCoverageFrom": [
"**/*.{ts,tsx}", "**/*.{ts,tsx}",

View File

@ -4,4 +4,5 @@ module.exports = {
semi: false, semi: false,
singleQuote: true, singleQuote: true,
trailingComma: 'all', trailingComma: 'all',
}; arrowParens: 'avoid'
}

View File

@ -24,9 +24,7 @@ export class CanvasContext {
const webGLInfo = this.gl.getWebGLInfo() const webGLInfo = this.gl.getWebGLInfo()
if (webGLInfo) { if (webGLInfo) {
console.log( console.log(
`WebGL initialized. renderer: ${webGLInfo.renderer}, vendor: ${ `WebGL initialized. renderer: ${webGLInfo.renderer}, vendor: ${webGLInfo.vendor}, version: ${webGLInfo.version}`,
webGLInfo.vendor
}, version: ${webGLInfo.version}`,
) )
} }
;(window as any)['testContextLoss'] = () => { ;(window as any)['testContextLoss'] = () => {

View File

@ -175,8 +175,8 @@ export class FlamechartRenderer {
// and the blue channel to indicate the color bucket to render. // and the blue channel to indicate the color bucket to render.
// We add one to each so we have zero reserved for the background color. // We add one to each so we have zero reserved for the background color.
const color = new Color( const color = new Color(
(1 + i % 255) / 256, (1 + (i % 255)) / 256,
(1 + stackDepth % 255) / 256, (1 + (stackDepth % 255)) / 256,
(1 + this.flamechart.getColorBucketForFrame(frame.node.frame)) / 256, (1 + this.flamechart.getColorBucketForFrame(frame.node.frame)) / 256,
) )
batch.addRect(configSpaceBounds, color) batch.addRect(configSpaceBounds, color)
@ -288,10 +288,10 @@ export class FlamechartRenderer {
const configSpaceContentWidth = this.flamechart.getTotalWeight() const configSpaceContentWidth = this.flamechart.getTotalWeight()
const numAtlasEntriesPerLayer = Math.pow(2, zoomLevel) const numAtlasEntriesPerLayer = Math.pow(2, zoomLevel)
const left = Math.floor( const left = Math.floor(
numAtlasEntriesPerLayer * configSpaceSrcRect.left() / configSpaceContentWidth, (numAtlasEntriesPerLayer * configSpaceSrcRect.left()) / configSpaceContentWidth,
) )
const right = Math.ceil( const right = Math.ceil(
numAtlasEntriesPerLayer * configSpaceSrcRect.right() / configSpaceContentWidth, (numAtlasEntriesPerLayer * configSpaceSrcRect.right()) / configSpaceContentWidth,
) )
const nLayers = this.flamechart.getLayers().length const nLayers = this.flamechart.getLayers().length

View File

@ -65,7 +65,12 @@ export class ViewportRectangleRenderer {
private buffer: Graphics.VertexBuffer private buffer: Graphics.VertexBuffer
constructor(private gl: Graphics.Context) { constructor(private gl: Graphics.Context) {
const vertices = [[-1, 1], [1, 1], [-1, -1], [1, -1]] const vertices = [
[-1, 1],
[1, 1],
[-1, -1],
[1, -1],
]
const floats: number[] = [] const floats: number[] = []
for (let v of vertices) { for (let v of vertices) {
floats.push(v[0]) floats.push(v[0])

View File

@ -45,7 +45,14 @@ export class RectangleBatch {
return this.buffer return this.buffer
} }
const corners = [[0, 0], [1, 0], [0, 1], [1, 0], [0, 1], [1, 1]] const corners = [
[0, 0],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 1],
]
const bytes = new Uint8Array(vertexFormat.stride * corners.length * this.rects.length) const bytes = new Uint8Array(vertexFormat.stride * corners.length * this.rects.length)
const floats = new Float32Array(bytes.buffer) const floats = new Float32Array(bytes.buffer)

View File

@ -516,97 +516,6 @@ exports[`importFromChromeTimeline Chrome 69: indexToView 1`] = `0`;
exports[`importFromChromeTimeline Chrome 69: profileGroup.name 1`] = `"simple.json"`; exports[`importFromChromeTimeline Chrome 69: profileGroup.name 1`] = `"simple.json"`;
exports[`importFromChromeTimeline Workers Chrome 66 1`] = ` exports[`importFromChromeTimeline Workers Chrome 66 1`] = `
Object {
"frames": Array [
Frame {
"col": -1,
"file": "",
"key": "(program)::-1:-1",
"line": -1,
"name": "(program)",
"selfWeight": 819120,
"totalWeight": 819120,
},
Frame {
"col": 20,
"file": "http://172.30.3.176:7777/worker.js",
"key": "onmessage:http://172.30.3.176:7777/worker.js:14:20",
"line": 14,
"name": "onmessage",
"selfWeight": 639,
"totalWeight": 857719,
},
Frame {
"col": 14,
"file": "http://172.30.3.176:7777/worker.js",
"key": "alpha:http://172.30.3.176:7777/worker.js:8:14",
"line": 8,
"name": "alpha",
"selfWeight": 19976,
"totalWeight": 835149,
},
Frame {
"col": 14,
"file": "http://172.30.3.176:7777/worker.js",
"key": "gamma:http://172.30.3.176:7777/worker.js:0:14",
"line": 0,
"name": "gamma",
"selfWeight": 22197,
"totalWeight": 30000,
},
Frame {
"col": -1,
"file": "",
"key": "postMessage::-1:-1",
"line": -1,
"name": "postMessage",
"selfWeight": 1278,
"totalWeight": 21931,
},
],
"name": "worker.json - DedicatedWorker thread",
"stacks": Array [
" 9.07ms",
"(program) 5.49ms",
"onmessage;alpha;gamma 3.69ms",
"onmessage;postMessage 212.00µs",
"onmessage;postMessage;(program) 3.97ms",
"onmessage;alpha;gamma 3.82ms",
"onmessage;postMessage 414.00µs",
"onmessage;postMessage;(program) 3.71ms",
"onmessage;alpha;gamma 1.13ms",
"onmessage 188.00µs",
"onmessage;alpha;gamma 2.48ms",
"onmessage;alpha;gamma;(program) 3.89ms",
"onmessage;alpha;gamma 373.00µs",
"onmessage;alpha 184.00µs",
"onmessage;alpha;gamma 3.36ms",
"onmessage;alpha;gamma;(program) 3.91ms",
"onmessage;alpha;gamma 3.94ms",
"onmessage;postMessage 205.00µs",
"onmessage;postMessage;(program) 3.91ms",
"onmessage 451.00µs",
"onmessage;alpha;gamma 566.00µs",
"onmessage;alpha 194.00µs",
"onmessage;alpha;gamma 2.09ms",
"onmessage;alpha 189.00µs",
"onmessage;alpha;gamma 746.00µs",
"onmessage;postMessage 211.00µs",
"onmessage;postMessage;(program) 4.00ms",
"onmessage;alpha 4.80ms",
"onmessage;alpha;(program) 5.28ms",
"onmessage;alpha 4.70ms",
"onmessage;postMessage 236.00µs",
"onmessage;postMessage;(program) 5.06ms",
"onmessage;alpha 5.07ms",
"onmessage;alpha;(program) 4.81ms",
"onmessage;alpha 4.84ms",
"onmessage;alpha;(program) 775.08ms",
],
}
`;
exports[`importFromChromeTimeline Workers Chrome 66 2`] = `
Object { Object {
"frames": Array [ "frames": Array [
Frame { Frame {
@ -913,7 +822,98 @@ Object {
} }
`; `;
exports[`importFromChromeTimeline Workers Chrome 66: indexToView 1`] = `1`; exports[`importFromChromeTimeline Workers Chrome 66 2`] = `
Object {
"frames": Array [
Frame {
"col": -1,
"file": "",
"key": "(program)::-1:-1",
"line": -1,
"name": "(program)",
"selfWeight": 819120,
"totalWeight": 819120,
},
Frame {
"col": 20,
"file": "http://172.30.3.176:7777/worker.js",
"key": "onmessage:http://172.30.3.176:7777/worker.js:14:20",
"line": 14,
"name": "onmessage",
"selfWeight": 639,
"totalWeight": 857719,
},
Frame {
"col": 14,
"file": "http://172.30.3.176:7777/worker.js",
"key": "alpha:http://172.30.3.176:7777/worker.js:8:14",
"line": 8,
"name": "alpha",
"selfWeight": 19976,
"totalWeight": 835149,
},
Frame {
"col": 14,
"file": "http://172.30.3.176:7777/worker.js",
"key": "gamma:http://172.30.3.176:7777/worker.js:0:14",
"line": 0,
"name": "gamma",
"selfWeight": 22197,
"totalWeight": 30000,
},
Frame {
"col": -1,
"file": "",
"key": "postMessage::-1:-1",
"line": -1,
"name": "postMessage",
"selfWeight": 1278,
"totalWeight": 21931,
},
],
"name": "worker.json - DedicatedWorker thread",
"stacks": Array [
" 9.07ms",
"(program) 5.49ms",
"onmessage;alpha;gamma 3.69ms",
"onmessage;postMessage 212.00µs",
"onmessage;postMessage;(program) 3.97ms",
"onmessage;alpha;gamma 3.82ms",
"onmessage;postMessage 414.00µs",
"onmessage;postMessage;(program) 3.71ms",
"onmessage;alpha;gamma 1.13ms",
"onmessage 188.00µs",
"onmessage;alpha;gamma 2.48ms",
"onmessage;alpha;gamma;(program) 3.89ms",
"onmessage;alpha;gamma 373.00µs",
"onmessage;alpha 184.00µs",
"onmessage;alpha;gamma 3.36ms",
"onmessage;alpha;gamma;(program) 3.91ms",
"onmessage;alpha;gamma 3.94ms",
"onmessage;postMessage 205.00µs",
"onmessage;postMessage;(program) 3.91ms",
"onmessage 451.00µs",
"onmessage;alpha;gamma 566.00µs",
"onmessage;alpha 194.00µs",
"onmessage;alpha;gamma 2.09ms",
"onmessage;alpha 189.00µs",
"onmessage;alpha;gamma 746.00µs",
"onmessage;postMessage 211.00µs",
"onmessage;postMessage;(program) 4.00ms",
"onmessage;alpha 4.80ms",
"onmessage;alpha;(program) 5.28ms",
"onmessage;alpha 4.70ms",
"onmessage;postMessage 236.00µs",
"onmessage;postMessage;(program) 5.06ms",
"onmessage;alpha 5.07ms",
"onmessage;alpha;(program) 4.81ms",
"onmessage;alpha 4.84ms",
"onmessage;alpha;(program) 775.08ms",
],
}
`;
exports[`importFromChromeTimeline Workers Chrome 66: indexToView 1`] = `0`;
exports[`importFromChromeTimeline Workers Chrome 66: profileGroup.name 1`] = `"worker.json"`; exports[`importFromChromeTimeline Workers Chrome 66: profileGroup.name 1`] = `"worker.json"`;

View File

@ -44,17 +44,8 @@ Object {
"key": "A", "key": "A",
"line": undefined, "line": undefined,
"name": "A", "name": "A",
"selfWeight": 1, "selfWeight": 2,
"totalWeight": 10, "totalWeight": 6,
},
Frame {
"col": undefined,
"file": undefined,
"key": "C",
"line": undefined,
"name": "C",
"selfWeight": 3,
"totalWeight": 10,
}, },
Frame { Frame {
"col": undefined, "col": undefined,
@ -62,9 +53,18 @@ Object {
"key": "B", "key": "B",
"line": undefined, "line": undefined,
"name": "B", "name": "B",
"selfWeight": 3, "selfWeight": 2,
"totalWeight": 4, "totalWeight": 4,
}, },
Frame {
"col": undefined,
"file": undefined,
"key": "C",
"line": undefined,
"name": "C",
"selfWeight": 2,
"totalWeight": 2,
},
Frame { Frame {
"col": undefined, "col": undefined,
"file": undefined, "file": undefined,
@ -77,12 +77,14 @@ Object {
], ],
"name": "pid 0, tid 1", "name": "pid 0, tid 1",
"stacks": Array [ "stacks": Array [
"A;C;B 2.00µs", "A;B;C 1.00µs",
"A;C 2.00µs", "A;B 1.00µs",
"A;C;A 1.00µs", "A 1.00µs",
"A;C;A;B 1.00µs", " 1.00µs",
"A;C;A;B;C 1.00µs", "A 1.00µs",
"A;C;X 3.00µs", "A;B 1.00µs",
"A;B;C 1.00µs",
"X 3.00µs",
], ],
} }
`; `;

51
src/jest-setup.js Normal file
View File

@ -0,0 +1,51 @@
// Versions of node before 10 had an unstable sort. This isn't really an issue in browsers
// that speedscope supports, but for the purposes of supporting node 10, we'll polyfill
// a stable sort to make the tests pass.
//
// See:
// - https://v8.dev/features/stable-sort
// - https://v8.dev/blog/array-sort
// - https://github.com/jlfwong/speedscope/pull/254#issuecomment-575116995
//
// Once we stop supporting node 10, this can be removed.
//
// An alternative would be to change our sort implementation to be stable by definition
// rather than relying upon native sort being stable. I don't want to do that because
// we'd take a perf hit.
//
// Because we're not going to use this in our actual build, it's okay for this
// to be inefficient.
(function () {
const nodeVersion = process.versions.node
const versionParts = nodeVersion.split('.')
const majorVersion = parseInt(versionParts[0], 10)
if (majorVersion > 10) {
// Don't need to do the patch for newer node versions
return
}
const defaultCompareFunction = (a, b) => {
const sa = '' + a
const sb = '' + b
if (sa < sb) return -1
if (sa > sb) return 1
return 0
}
const originalSort = Array.prototype.sort
Array.prototype.sort = function (compareFunction) {
const arrayWithIndices = this.map((x, i) => [x, i])
originalSort.call(arrayWithIndices, (a, b) => {
if (!compareFunction) {
compareFunction = defaultCompareFunction
}
const res = compareFunction(a[0], b[0])
if (res !== 0) return res
return a[1] < b[1] ? -1 : 1
})
this.splice(0, this.length, ...arrayWithIndices.map(x => x[0]))
return this
}
})()

View File

@ -15,7 +15,7 @@ export class Color {
// https://en.wikipedia.org/wiki/HSL_and_HSV#From_luma/chroma/hue // https://en.wikipedia.org/wiki/HSL_and_HSV#From_luma/chroma/hue
const hPrime = H / 60 const hPrime = H / 60
const X = C * (1 - Math.abs(hPrime % 2 - 1)) const X = C * (1 - Math.abs((hPrime % 2) - 1))
const [R1, G1, B1] = const [R1, G1, B1] =
hPrime < 1 hPrime < 1
? [C, X, 0] ? [C, X, 0]

View File

@ -11,7 +11,13 @@ test('importEmscriptenSymbolMap', () => {
'c:C', 'c:C',
].join('\n'), ].join('\n'),
), ),
).toEqual(new Map([['a', 'A'], ['b', 'B'], ['c', 'C']])) ).toEqual(
new Map([
['a', 'A'],
['b', 'B'],
['c', 'C'],
]),
)
// Valid symbol map with trailing newline // Valid symbol map with trailing newline
expect( expect(
@ -25,7 +31,14 @@ test('importEmscriptenSymbolMap', () => {
'', '',
].join('\n'), ].join('\n'),
), ),
).toEqual(new Map([['a', 'A'], ['b', 'B'], ['c', 'C'], ['d', 'D-D']])) ).toEqual(
new Map([
['a', 'A'],
['b', 'B'],
['c', 'C'],
['d', 'D-D'],
]),
)
// Valid symbol map with non-alpha characters // Valid symbol map with non-alpha characters
expect(importEmscriptenSymbolMap('u6:__ZN8tinyxml210XMLCommentD0Ev\n')).toEqual( expect(importEmscriptenSymbolMap('u6:__ZN8tinyxml210XMLCommentD0Ev\n')).toEqual(

View File

@ -138,7 +138,10 @@ function importSpeedscopeProfile(
for (let i = 0; i < samples.length; i++) { for (let i = 0; i < samples.length; i++) {
const stack = samples[i] const stack = samples[i]
const weight = weights[i] const weight = weights[i]
profile.appendSampleWithWeight(stack.map(n => frameInfos[n]), weight) profile.appendSampleWithWeight(
stack.map(n => frameInfos[n]),
weight,
)
} }
return profile.build() return profile.build()

View File

@ -13,9 +13,10 @@ test('clamp', () => {
// Change this to jsc.integer to debug failures more easily // Change this to jsc.integer to debug failures more easily
let numericType = jsc.number let numericType = jsc.number
const arbitraryVec2 = jsc const arbitraryVec2 = jsc.record({x: jsc.integer, y: numericType}).smap(
.record({x: jsc.integer, y: numericType}) v => new Vec2(v.x, v.y),
.smap(v => new Vec2(v.x, v.y), v => v) v => v,
)
const positiveVec2 = jsc.suchthat(arbitraryVec2, v => v.x > 0 && v.y > 0) const positiveVec2 = jsc.suchthat(arbitraryVec2, v => v.x > 0 && v.y > 0)
@ -28,23 +29,25 @@ const arbitraryTransform = jsc
m11: numericType, m11: numericType,
m12: numericType, m12: numericType,
}) })
.smap(t => new AffineTransform(t.m00, t.m01, t.m02, t.m10, t.m11, t.m12), t => t) .smap(
t => new AffineTransform(t.m00, t.m01, t.m02, t.m10, t.m11, t.m12),
t => t,
)
const invertibleTransform = jsc.suchthat(arbitraryTransform, t => t.det() != 0) const invertibleTransform = jsc.suchthat(arbitraryTransform, t => t.det() != 0)
const simpleTransform = jsc.suchthat( const simpleTransform = jsc.suchthat(
jsc jsc.record({scale: arbitraryVec2, translation: arbitraryVec2}).smap(
.record({scale: arbitraryVec2, translation: arbitraryVec2})
.smap(
t => AffineTransform.withScale(t.scale).withTranslation(t.translation), t => AffineTransform.withScale(t.scale).withTranslation(t.translation),
t => ({scale: t.getScale(), translation: t.getTranslation()}), t => ({scale: t.getScale(), translation: t.getTranslation()}),
), ),
t => t.det() != 0, t => t.det() != 0,
) )
const arbitraryRect = jsc const arbitraryRect = jsc.record({origin: arbitraryVec2, size: positiveVec2}).smap(
.record({origin: arbitraryVec2, size: positiveVec2}) r => new Rect(r.origin, r.size),
.smap(r => new Rect(r.origin, r.size), r => r) r => r,
)
describe('Vec2', () => { describe('Vec2', () => {
test('constructor', () => { test('constructor', () => {
@ -263,51 +266,35 @@ describe('AffineTransform', () => {
expect(new AffineTransform(0, 0, 0, 0, 0, 0).inverted()).toBe(null) expect(new AffineTransform(0, 0, 0, 0, 0, 0).inverted()).toBe(null)
jsc.assertForall(invertibleTransform, t => { jsc.assertForall(invertibleTransform, t => {
return t return t.inverted()!.inverted()!.approxEquals(t)
.inverted()!
.inverted()!
.approxEquals(t)
}) })
}) })
test('translation', () => { test('translation', () => {
jsc.assertForall(arbitraryTransform, arbitraryVec2, (t, v1) => { jsc.assertForall(arbitraryTransform, arbitraryVec2, (t, v1) => {
return t return t.withTranslation(v1).getTranslation().equals(v1)
.withTranslation(v1)
.getTranslation()
.equals(v1)
}) })
jsc.assertForall(arbitraryTransform, arbitraryVec2, (t, v1) => { jsc.assertForall(arbitraryTransform, arbitraryVec2, (t, v1) => {
const initialTranslation = t.getTranslation() const initialTranslation = t.getTranslation()
return t return t.translatedBy(v1).getTranslation().approxEquals(initialTranslation.plus(v1))
.translatedBy(v1)
.getTranslation()
.approxEquals(initialTranslation.plus(v1))
}) })
}) })
test('scale', () => { test('scale', () => {
jsc.assertForall(arbitraryTransform, arbitraryVec2, (t, v1) => { jsc.assertForall(arbitraryTransform, arbitraryVec2, (t, v1) => {
return t return t.withScale(v1).getScale().equals(v1)
.withScale(v1)
.getScale()
.equals(v1)
}) })
}) })
test('transformVector', () => { test('transformVector', () => {
// Vector transformation are translation-invariant // Vector transformation are translation-invariant
jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => { jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => {
return AffineTransform.withTranslation(v1) return AffineTransform.withTranslation(v1).transformVector(v2).approxEquals(v2)
.transformVector(v2)
.approxEquals(v2)
}) })
jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => { jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => {
return AffineTransform.withScale(v1) return AffineTransform.withScale(v1).transformVector(v2).approxEquals(v2.timesPointwise(v1))
.transformVector(v2)
.approxEquals(v2.timesPointwise(v1))
}) })
}) })
@ -319,15 +306,11 @@ describe('AffineTransform', () => {
test('transformPosition', () => { test('transformPosition', () => {
jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => { jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => {
return AffineTransform.withTranslation(v1) return AffineTransform.withTranslation(v1).transformPosition(v2).approxEquals(v2.plus(v1))
.transformPosition(v2)
.approxEquals(v2.plus(v1))
}) })
jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => { jsc.assertForall(arbitraryVec2, arbitraryVec2, (v1, v2) => {
return AffineTransform.withScale(v1) return AffineTransform.withScale(v1).transformPosition(v2).approxEquals(v2.timesPointwise(v1))
.transformPosition(v2)
.approxEquals(v2.timesPointwise(v1))
}) })
}) })
@ -359,10 +342,7 @@ describe('AffineTransform', () => {
test('times', () => { test('times', () => {
jsc.assertForall(invertibleTransform, invertibleTransform, (t1, t2) => { jsc.assertForall(invertibleTransform, invertibleTransform, (t1, t2) => {
return t1 return t1.times(t2).times(t2.inverted()!).approxEquals(t1)
.times(t2)
.times(t2.inverted()!)
.approxEquals(t1)
}) })
}) })
}) })

View File

@ -26,19 +26,22 @@ function toStackList(profile: Profile, grouped: boolean): string[] {
const curStack: (number | string)[] = [] const curStack: (number | string)[] = []
let lastValue = 0 let lastValue = 0
function openFrame(node: CallTreeNode, value: number) { function maybeEmit(value: number) {
if (lastValue != value) { if (lastValue != value) {
stackList.push(curStack.map(k => `${k}`).join(';')) stackList.push(
curStack.map(k => `${k}`).join(';') + ` ${profile.formatValue(value - lastValue)}`,
)
lastValue = value lastValue = value
} }
curStack.push(node.frame.key) }
function openFrame(node: CallTreeNode, value: number) {
maybeEmit(value)
curStack.push(node.frame.name)
} }
function closeFrame(node: CallTreeNode, value: number) { function closeFrame(node: CallTreeNode, value: number) {
if (lastValue != value) { maybeEmit(value)
stackList.push(curStack.map(k => `${k}`).join(';'))
lastValue = value
}
curStack.pop() curStack.pop()
} }
@ -82,49 +85,49 @@ function verifyProfile(profile: Profile) {
expect(toStackList(profile, false)).toEqual([ expect(toStackList(profile, false)).toEqual([
// prettier-ignore // prettier-ignore
'a', 'a 1',
'a;b', 'a;b 2',
'a;b;d', 'a;b;d 1',
'a;b;c', 'a;b;c 1',
'', ' 1',
'a', 'a 1',
'a;b', 'a;b 1',
'a;b;b', 'a;b;b 1',
'a;b;e', 'a;b;e 1',
'a', 'a 1',
]) ])
expect(toStackList(profile, true)).toEqual([ expect(toStackList(profile, true)).toEqual([
// prettier-ignore // prettier-ignore
'a;b;e', 'a;b;d 1',
'a;b;b', 'a;b;c 1',
'a;b;c', 'a;b;b 1',
'a;b;d', 'a;b;e 1',
'a;b', 'a;b 3',
'a', 'a 3',
]) ])
const flattened = profile.getProfileWithRecursionFlattened() const flattened = profile.getProfileWithRecursionFlattened()
expect(toStackList(flattened, false)).toEqual([ expect(toStackList(flattened, false)).toEqual([
// prettier-ignore // prettier-ignore
'a', 'a 1',
'a;b', 'a;b 2',
'a;b;d', 'a;b;d 1',
'a;b;c', 'a;b;c 1',
'', ' 1',
'a', 'a 1',
'a;b', 'a;b 2',
'a;b;e', 'a;b;e 1',
'a', 'a 1',
]) ])
expect(toStackList(flattened, true)).toEqual([ expect(toStackList(flattened, true)).toEqual([
// prettier-ignore // prettier-ignore
'a;b;e', 'a;b;d 1',
'a;b;c', 'a;b;c 1',
'a;b;d', 'a;b;e 1',
'a;b', 'a;b 4',
'a', 'a 3',
]) ])
} }
@ -259,9 +262,9 @@ test('getInvertedProfileForCallersOf', () => {
expect(toStackList(inverted, false)).toEqual([ expect(toStackList(inverted, false)).toEqual([
// prettier-ignore // prettier-ignore
'b', 'b 1',
'b;a', 'b;a 3',
'b;d', 'b;d 1',
]) ])
}) })
@ -287,10 +290,10 @@ test('getProfileForCalleesOf', () => {
expect(toStackList(inverted, false)).toEqual([ expect(toStackList(inverted, false)).toEqual([
// prettier-ignore // prettier-ignore
'b', 'b 2',
'b;c', 'b;c 1',
'b;d', 'b;d 1',
'b', 'b 1',
]) ])
}) })
@ -313,8 +316,8 @@ test('getProfileWithRecursionFlattened', () => {
expect(toStackList(inverted, false)).toEqual([ expect(toStackList(inverted, false)).toEqual([
// prettier-ignore // prettier-ignore
'a', 'a 1',
'a;b', 'a;b 3',
]) ])
const framesInProfile = new Set<string | number>() const framesInProfile = new Set<string | number>()

View File

@ -181,7 +181,7 @@ export class Profile {
let childTime = 0 let childTime = 0
const children = [...node.children] const children = [...node.children]
children.sort((a, b) => (a.getTotalWeight() > b.getTotalWeight() ? -1 : 1)) children.sort((a, b) => -(a.getTotalWeight() - b.getTotalWeight()))
children.forEach(function (child) { children.forEach(function (child) {
visit(child, start + childTime) visit(child, start + childTime)
@ -507,7 +507,10 @@ export class StackListProfileBuilder extends Profile {
this.setValueFormatter(new RawValueFormatter()) this.setValueFormatter(new RawValueFormatter())
} }
} }
this.totalWeight = Math.max(this.totalWeight, this.weights.reduce((a, b) => a + b, 0)) this.totalWeight = Math.max(
this.totalWeight,
this.weights.reduce((a, b) => a + b, 0),
)
return this return this
} }
} }
@ -557,9 +560,7 @@ export class CallTreeProfileBuilder extends Profile {
this.weights.push(value - this.lastValue) this.weights.push(value - this.lastValue)
} else if (delta < 0) { } else if (delta < 0) {
throw new Error( throw new Error(
`Samples must be provided in increasing order of cumulative value. Last sample was ${ `Samples must be provided in increasing order of cumulative value. Last sample was ${this.lastValue}, this sample was ${value}`,
this.lastValue
}, this sample was ${value}`,
) )
} }
} }

View File

@ -53,7 +53,7 @@ export class StatsPanel {
this.msPanel.update(time - this.beginTime, 200) this.msPanel.update(time - this.beginTime, 200)
if (time >= this.prevTime + 1000) { if (time >= this.prevTime + 1000) {
this.fpsPanel.update(this.frames * 1000 / (time - this.prevTime), 100) this.fpsPanel.update((this.frames * 1000) / (time - this.prevTime), 100)
this.prevTime = time this.prevTime = time
this.frames = 0 this.frames = 0
} }

View File

@ -4,7 +4,9 @@ export function lastOf<T>(ts: T[]): T | null {
export function sortBy<T>(ts: T[], key: (t: T) => number | string): void { export function sortBy<T>(ts: T[], key: (t: T) => number | string): void {
function comparator(a: T, b: T) { function comparator(a: T, b: T) {
return key(a) < key(b) ? -1 : 1 const keyA = key(a)
const keyB = key(b)
return keyA < keyB ? -1 : keyA > keyB ? 1 : 0
} }
ts.sort(comparator) ts.sort(comparator)
} }
@ -178,7 +180,8 @@ export function lazyStatic<T>(cb: () => T): () => T {
} }
} }
const base64lookupTable = lazyStatic((): Map<string, number> => { const base64lookupTable = lazyStatic(
(): Map<string, number> => {
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
const ret = new Map<string, number>() const ret = new Map<string, number>()
for (let i = 0; i < alphabet.length; i++) { for (let i = 0; i < alphabet.length; i++) {
@ -186,7 +189,8 @@ const base64lookupTable = lazyStatic((): Map<string, number> => {
} }
ret.set('=', -1) ret.set('=', -1)
return ret return ret
}) },
)
// NOTE: There are probably simpler solutions to this problem, but I have this written already, so // 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. // until we run into problems with this, let's just use this.
@ -210,9 +214,7 @@ export function decodeBase64(encoded: string): Uint8Array {
if (encoded.length % 4 !== 0) { if (encoded.length % 4 !== 0) {
throw new Error( throw new Error(
`Invalid length for base64 encoded string. Expected length % 4 = 0, got length = ${ `Invalid length for base64 encoded string. Expected length % 4 = 0, got length = ${encoded.length}`,
encoded.length
}`,
) )
} }

View File

@ -49,10 +49,8 @@ export const getProfileToView = memoizeByShallowEquality(
return flattenRecursion ? profile.getProfileWithRecursionFlattened() : profile return flattenRecursion ? profile.getProfileWithRecursionFlattened() : profile
}, },
) )
export const getFrameToColorBucket = memoizeByReference((profile: Profile): Map< export const getFrameToColorBucket = memoizeByReference(
string | number, (profile: Profile): Map<string | number, number> => {
number
> => {
const frames: Frame[] = [] const frames: Frame[] = []
profile.forEachFrame(f => frames.push(f)) profile.forEachFrame(f => frames.push(f))
function key(f: Frame) { function key(f: Frame) {
@ -64,8 +62,9 @@ export const getFrameToColorBucket = memoizeByReference((profile: Profile): Map<
frames.sort(compare) frames.sort(compare)
const frameToColorBucket = new Map<string | number, number>() const frameToColorBucket = new Map<string | number, number>()
for (let i = 0; i < frames.length; i++) { for (let i = 0; i < frames.length; i++) {
frameToColorBucket.set(frames[i].key, Math.floor(255 * i / frames.length)) frameToColorBucket.set(frames[i].key, Math.floor((255 * i) / frames.length))
} }
return frameToColorBucket return frameToColorBucket
}) },
)

View File

@ -678,7 +678,7 @@ export class Application extends StatelessComponent<ApplicationProps> {
<Toolbar <Toolbar
saveFile={this.saveFile} saveFile={this.saveFile}
browseForFile={this.browseForFile} browseForFile={this.browseForFile}
{...this.props as ApplicationProps} {...(this.props as ApplicationProps)}
/> />
<div className={css(style.contentContainer)}>{this.renderContent()}</div> <div className={css(style.contentContainer)}>{this.renderContent()}</div>
{this.props.dragActive && <div className={css(style.dragTarget)} />} {this.props.dragActive && <div className={css(style.dragTarget)} />}

View File

@ -19,8 +19,8 @@ class StatisticsTable extends Component<StatisticsTableProps, {}> {
render() { render() {
const total = this.props.formatter(this.props.selectedTotal) const total = this.props.formatter(this.props.selectedTotal)
const self = this.props.formatter(this.props.selectedSelf) const self = this.props.formatter(this.props.selectedSelf)
const totalPerc = 100.0 * this.props.selectedTotal / this.props.grandTotal const totalPerc = (100.0 * this.props.selectedTotal) / this.props.grandTotal
const selfPerc = 100.0 * this.props.selectedSelf / this.props.grandTotal const selfPerc = (100.0 * this.props.selectedSelf) / this.props.grandTotal
return ( return (
<div className={css(style.statsTable)}> <div className={css(style.statsTable)}>

View File

@ -120,9 +120,7 @@ export class FlamechartMinimapView extends Component<FlamechartMinimapViewProps,
const physicalViewSpaceFontSize = FontSize.LABEL * window.devicePixelRatio const physicalViewSpaceFontSize = FontSize.LABEL * window.devicePixelRatio
const labelPaddingPx = (physicalViewSpaceFrameHeight - physicalViewSpaceFontSize) / 2 const labelPaddingPx = (physicalViewSpaceFrameHeight - physicalViewSpaceFontSize) / 2
ctx.font = `${physicalViewSpaceFontSize}px/${physicalViewSpaceFrameHeight}px ${ ctx.font = `${physicalViewSpaceFontSize}px/${physicalViewSpaceFrameHeight}px ${FontFamily.MONOSPACE}`
FontFamily.MONOSPACE
}`
ctx.textBaseline = 'top' ctx.textBaseline = 'top'
const minInterval = Math.pow(10, Math.floor(Math.log10(targetInterval))) const minInterval = Math.pow(10, Math.floor(Math.log10(targetInterval)))

View File

@ -181,9 +181,7 @@ export class FlamechartPanZoomView extends Component<FlamechartPanZoomViewProps,
) )
} }
ctx.font = `${physicalViewSpaceFontSize}px/${physicalViewSpaceFrameHeight}px ${ ctx.font = `${physicalViewSpaceFontSize}px/${physicalViewSpaceFrameHeight}px ${FontFamily.MONOSPACE}`
FontFamily.MONOSPACE
}`
ctx.textBaseline = 'alphabetic' ctx.textBaseline = 'alphabetic'
ctx.fillStyle = Colors.DARK_GRAY ctx.fillStyle = Colors.DARK_GRAY

View File

@ -62,7 +62,7 @@ export class FlamechartView extends StatelessComponent<FlamechartViewProps> {
formatValue(weight: number) { formatValue(weight: number) {
const totalWeight = this.props.flamechart.getTotalWeight() const totalWeight = this.props.flamechart.getTotalWeight()
const percent = 100 * weight / totalWeight const percent = (100 * weight) / totalWeight
const formattedPercent = formatPercent(percent) const formattedPercent = formatPercent(percent)
return `${this.props.flamechart.formatValue(weight)} (${formattedPercent})` return `${this.props.flamechart.formatValue(weight)} (${formattedPercent})`
} }

View File

@ -34,7 +34,7 @@ export class FlamechartWrapper extends StatelessComponent<FlamechartViewProps> {
} }
private formatValue(weight: number) { private formatValue(weight: number) {
const totalWeight = this.props.flamechart.getTotalWeight() const totalWeight = this.props.flamechart.getTotalWeight()
const percent = 100 * weight / totalWeight const percent = (100 * weight) / totalWeight
const formattedPercent = formatPercent(percent) const formattedPercent = formatPercent(percent)
return `${this.props.flamechart.formatValue(weight)} (${formattedPercent})` return `${this.props.flamechart.formatValue(weight)} (${formattedPercent})`
} }

View File

@ -83,8 +83,8 @@ export class ProfileTableView extends Component<ProfileTableViewProps, void> {
const totalWeight = frame.getTotalWeight() const totalWeight = frame.getTotalWeight()
const selfWeight = frame.getSelfWeight() const selfWeight = frame.getSelfWeight()
const totalPerc = 100.0 * totalWeight / profile.getTotalNonIdleWeight() const totalPerc = (100.0 * totalWeight) / profile.getTotalNonIdleWeight()
const selfPerc = 100.0 * selfWeight / profile.getTotalNonIdleWeight() const selfPerc = (100.0 * selfWeight) / profile.getTotalNonIdleWeight()
const selected = frame === selectedFrame const selected = frame === selectedFrame