mirror of
https://github.com/jlfwong/speedscope.git
synced 2024-11-22 22:14:25 +03:00
Fixes #182 by adding support for importing the JSON profiling format created by GHC's built in profiling support when the executable is passed the `-pj` option. Produces a profile group containing both a time and allocation profile. Unfortunately, GHC doesn't provide the raw sample information to get the time view to be useful, so only left heavy and sandwich are useful. Includes a test profile, and I've also tested it on a more real large 2MB profile file in the UI and it works great. I also modified the Readme to link to a wiki page I'm unable to create, but that should have something like this content copy-pasted into it: # Importing from Haskell GHC provides built in profiling support that can export a JSON file. In order to do this you need to compile your executable with profiling support and then pass the `-pj` RTS flag to the executable. This will produce a `my-binary.prof` file in the current directory which you can import into speedscope. ## Using GHC See the [GHC manual page on profiling](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html) for more extensive information on the command line flags available. ``` $ ghc -prof -fprof-auto -rtsopts Main.hs $ ./Main +RTS -pj -RTS ``` ## Using Stack ### With executables ``` $ stack build --profile $ stack exec -- my-executable +RTS -pj -RTS ``` ### With tests ``` stack test --profile --test-arguments "+RTS -pj -RTS" ```
This commit is contained in:
parent
86f4ba636d
commit
e35335fe3c
@ -45,6 +45,7 @@ speedscope is designed to ingest profiles from a variety of different profilers
|
||||
- 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 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).
|
||||
|
193
sample/profiles/haskell/simple.prof
Normal file
193
sample/profiles/haskell/simple.prof
Normal file
File diff suppressed because one or more lines are too long
864
src/import/__snapshots__/haskell.test.ts.snap
Normal file
864
src/import/__snapshots__/haskell.test.ts.snap
Normal file
@ -0,0 +1,864 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`importFromHaskell 1`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 144,
|
||||
"line": undefined,
|
||||
"name": "MAIN.MAIN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 798,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 56,
|
||||
"line": undefined,
|
||||
"name": "GHC.Conc.Signal.CAF",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 73,
|
||||
"line": undefined,
|
||||
"name": "GHC.IO.Encoding.CAF",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 75,
|
||||
"line": undefined,
|
||||
"name": "GHC.IO.Encoding.Iconv.CAF",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 84,
|
||||
"line": undefined,
|
||||
"name": "GHC.IO.Handle.FD.CAF",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 119,
|
||||
"line": undefined,
|
||||
"name": "Text.Printf.CAF",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 26,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:eta1_r6nI",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(21,1)-(38,42)",
|
||||
"key": 19,
|
||||
"line": undefined,
|
||||
"name": "Main.main",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 733,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(56,1)-(57,42)",
|
||||
"key": 4,
|
||||
"line": undefined,
|
||||
"name": "Main.check",
|
||||
"selfWeight": 320,
|
||||
"totalWeight": 320,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:31:9-29",
|
||||
"key": 16,
|
||||
"line": undefined,
|
||||
"name": "Main.main.long",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 28,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:eta_r6nG",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 35,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:io1",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 27,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:lvl2_r6nH",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 3,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(61,1)-(63,26)",
|
||||
"key": 3,
|
||||
"line": undefined,
|
||||
"name": "Main.make",
|
||||
"selfWeight": 406,
|
||||
"totalWeight": 409,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:63:19-26",
|
||||
"key": 1,
|
||||
"line": undefined,
|
||||
"name": "Main.make.d2",
|
||||
"selfWeight": 2,
|
||||
"totalWeight": 2,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:63:9-16",
|
||||
"key": 2,
|
||||
"line": undefined,
|
||||
"name": "Main.make.i2",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 1,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 24,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:lvl4_r6nL",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 22,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:lvl8_r6nP",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 21,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main1",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 29,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main11",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:27:9-35",
|
||||
"key": 15,
|
||||
"line": undefined,
|
||||
"name": "Main.main.c",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 8,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 30,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main12",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 23,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main5",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 31,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main7",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 25,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main9",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:23:9-12",
|
||||
"key": 33,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main_maxN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:23:9-35",
|
||||
"key": 13,
|
||||
"line": undefined,
|
||||
"name": "Main.main.maxN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:22:9",
|
||||
"key": 34,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main_n",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:22:9-14",
|
||||
"key": 12,
|
||||
"line": undefined,
|
||||
"name": "Main.main.n",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:24:9-16",
|
||||
"key": 32,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main_stretchN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:24:9-27",
|
||||
"key": 14,
|
||||
"line": undefined,
|
||||
"name": "Main.main.stretchN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:17:1-4",
|
||||
"key": 36,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:minN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:17:1-8",
|
||||
"key": 9,
|
||||
"line": undefined,
|
||||
"name": "Main.minN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 146,
|
||||
"line": undefined,
|
||||
"name": "GC.GC",
|
||||
"selfWeight": 46,
|
||||
"totalWeight": 46,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 147,
|
||||
"line": undefined,
|
||||
"name": "PROFILING.OVERHEAD_of",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 145,
|
||||
"line": undefined,
|
||||
"name": "SYSTEM.SYSTEM",
|
||||
"selfWeight": 19,
|
||||
"totalWeight": 19,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:35:26-54",
|
||||
"key": 18,
|
||||
"line": undefined,
|
||||
"name": "Main.main.\\\\",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:19:1-56",
|
||||
"key": 8,
|
||||
"line": undefined,
|
||||
"name": "Main.io",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:34:9-28",
|
||||
"key": 17,
|
||||
"line": undefined,
|
||||
"name": "Main.main.vs",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 721,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(42,1)-(45,38)",
|
||||
"key": 11,
|
||||
"line": undefined,
|
||||
"name": "Main.depth",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 721,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(49,1)-(52,31)",
|
||||
"key": 7,
|
||||
"line": undefined,
|
||||
"name": "Main.sumT",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 721,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:51:9-31",
|
||||
"key": 6,
|
||||
"line": undefined,
|
||||
"name": "Main.sumT.a",
|
||||
"selfWeight": 3,
|
||||
"totalWeight": 369,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:52:9-31",
|
||||
"key": 5,
|
||||
"line": undefined,
|
||||
"name": "Main.sumT.b",
|
||||
"selfWeight": 1,
|
||||
"totalWeight": 352,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:45:9-38",
|
||||
"key": 10,
|
||||
"line": undefined,
|
||||
"name": "Main.depth.n",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
],
|
||||
"name": "binary-trees time",
|
||||
"stacks": Array [
|
||||
"MAIN.MAIN;Main.CAF:eta1_r6nI;Main.main;Main.check 1.00ms",
|
||||
"MAIN.MAIN;Main.CAF:lvl2_r6nH;Main.main;Main.main.long;Main.make 3.00ms",
|
||||
"MAIN.MAIN;Main.CAF:main11;Main.main;Main.main.c;Main.check 4.00ms",
|
||||
"MAIN.MAIN;Main.CAF:main12;Main.main;Main.main.c;Main.make 4.00ms",
|
||||
"MAIN.MAIN;GC.GC 46.00ms",
|
||||
"MAIN.MAIN;SYSTEM.SYSTEM 19.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a;Main.check 153.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a;Main.make;Main.make.d2 2.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a;Main.make;Main.make.i2 1.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a;Main.make 210.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a 3.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.b;Main.check 162.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.b;Main.make 189.00ms",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.b 1.00ms",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromHaskell 2`] = `
|
||||
Object {
|
||||
"frames": Array [
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 144,
|
||||
"line": undefined,
|
||||
"name": "MAIN.MAIN",
|
||||
"selfWeight": 648,
|
||||
"totalWeight": 1921672664,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 56,
|
||||
"line": undefined,
|
||||
"name": "GHC.Conc.Signal.CAF",
|
||||
"selfWeight": 640,
|
||||
"totalWeight": 640,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 73,
|
||||
"line": undefined,
|
||||
"name": "GHC.IO.Encoding.CAF",
|
||||
"selfWeight": 2768,
|
||||
"totalWeight": 2768,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 75,
|
||||
"line": undefined,
|
||||
"name": "GHC.IO.Encoding.Iconv.CAF",
|
||||
"selfWeight": 200,
|
||||
"totalWeight": 200,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 84,
|
||||
"line": undefined,
|
||||
"name": "GHC.IO.Handle.FD.CAF",
|
||||
"selfWeight": 34704,
|
||||
"totalWeight": 34704,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 119,
|
||||
"line": undefined,
|
||||
"name": "Text.Printf.CAF",
|
||||
"selfWeight": 528,
|
||||
"totalWeight": 528,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 26,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:eta1_r6nI",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 2097152,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(21,1)-(38,42)",
|
||||
"key": 19,
|
||||
"line": undefined,
|
||||
"name": "Main.main",
|
||||
"selfWeight": 32,
|
||||
"totalWeight": 1921591544,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(56,1)-(57,42)",
|
||||
"key": 4,
|
||||
"line": undefined,
|
||||
"name": "Main.check",
|
||||
"selfWeight": 406149056,
|
||||
"totalWeight": 406149056,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:31:9-29",
|
||||
"key": 16,
|
||||
"line": undefined,
|
||||
"name": "Main.main.long",
|
||||
"selfWeight": 32,
|
||||
"totalWeight": 7864112,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 28,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:eta_r6nG",
|
||||
"selfWeight": 1096,
|
||||
"totalWeight": 1096,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 35,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:io1",
|
||||
"selfWeight": 1888,
|
||||
"totalWeight": 1888,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 27,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:lvl2_r6nH",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 7864112,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(61,1)-(63,26)",
|
||||
"key": 3,
|
||||
"line": undefined,
|
||||
"name": "Main.make",
|
||||
"selfWeight": 1512575520,
|
||||
"totalWeight": 1512575520,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:63:19-26",
|
||||
"key": 1,
|
||||
"line": undefined,
|
||||
"name": "Main.make.d2",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:63:9-16",
|
||||
"key": 2,
|
||||
"line": undefined,
|
||||
"name": "Main.make.i2",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 24,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:lvl4_r6nL",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 22,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:lvl8_r6nP",
|
||||
"selfWeight": 520,
|
||||
"totalWeight": 520,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 21,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main1",
|
||||
"selfWeight": 16,
|
||||
"totalWeight": 16,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 29,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main11",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 4194304,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:27:9-35",
|
||||
"key": 15,
|
||||
"line": undefined,
|
||||
"name": "Main.main.c",
|
||||
"selfWeight": 64,
|
||||
"totalWeight": 19922736,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 30,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main12",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 15728432,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 23,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main5",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 31,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main7",
|
||||
"selfWeight": 880,
|
||||
"totalWeight": 880,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 25,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main9",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:23:9-12",
|
||||
"key": 33,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main_maxN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 32,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:23:9-35",
|
||||
"key": 13,
|
||||
"line": undefined,
|
||||
"name": "Main.main.maxN",
|
||||
"selfWeight": 32,
|
||||
"totalWeight": 32,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:22:9",
|
||||
"key": 34,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main_n",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:22:9-14",
|
||||
"key": 12,
|
||||
"line": undefined,
|
||||
"name": "Main.main.n",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:24:9-16",
|
||||
"key": 32,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:main_stretchN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 32,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:24:9-27",
|
||||
"key": 14,
|
||||
"line": undefined,
|
||||
"name": "Main.main.stretchN",
|
||||
"selfWeight": 32,
|
||||
"totalWeight": 32,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:17:1-4",
|
||||
"key": 36,
|
||||
"line": undefined,
|
||||
"name": "Main.CAF:minN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:17:1-8",
|
||||
"key": 9,
|
||||
"line": undefined,
|
||||
"name": "Main.minN",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 146,
|
||||
"line": undefined,
|
||||
"name": "GC.GC",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 147,
|
||||
"line": undefined,
|
||||
"name": "PROFILING.OVERHEAD_of",
|
||||
"selfWeight": 2496,
|
||||
"totalWeight": 2496,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": undefined,
|
||||
"key": 145,
|
||||
"line": undefined,
|
||||
"name": "SYSTEM.SYSTEM",
|
||||
"selfWeight": 34736,
|
||||
"totalWeight": 34736,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:35:26-54",
|
||||
"key": 18,
|
||||
"line": undefined,
|
||||
"name": "Main.main.\\\\",
|
||||
"selfWeight": 2224,
|
||||
"totalWeight": 46672,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:19:1-56",
|
||||
"key": 8,
|
||||
"line": undefined,
|
||||
"name": "Main.io",
|
||||
"selfWeight": 67912,
|
||||
"totalWeight": 67912,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:34:9-28",
|
||||
"key": 17,
|
||||
"line": undefined,
|
||||
"name": "Main.main.vs",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1891637344,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(42,1)-(45,38)",
|
||||
"key": 11,
|
||||
"line": undefined,
|
||||
"name": "Main.depth",
|
||||
"selfWeight": 1120,
|
||||
"totalWeight": 1891637344,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:(49,1)-(52,31)",
|
||||
"key": 7,
|
||||
"line": undefined,
|
||||
"name": "Main.sumT",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 1891636224,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:51:9-31",
|
||||
"key": 6,
|
||||
"line": undefined,
|
||||
"name": "Main.sumT.a",
|
||||
"selfWeight": 1397760,
|
||||
"totalWeight": 945818112,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:52:9-31",
|
||||
"key": 5,
|
||||
"line": undefined,
|
||||
"name": "Main.sumT.b",
|
||||
"selfWeight": 1397760,
|
||||
"totalWeight": 945818112,
|
||||
},
|
||||
Frame {
|
||||
"col": undefined,
|
||||
"file": "src/Main.hs:45:9-38",
|
||||
"key": 10,
|
||||
"line": undefined,
|
||||
"name": "Main.depth.n",
|
||||
"selfWeight": 0,
|
||||
"totalWeight": 0,
|
||||
},
|
||||
],
|
||||
"name": "binary-trees allocation",
|
||||
"stacks": Array [
|
||||
"MAIN.MAIN;GHC.Conc.Signal.CAF 640 B",
|
||||
"MAIN.MAIN;GHC.IO.Encoding.CAF 2.70 KB",
|
||||
"MAIN.MAIN;GHC.IO.Encoding.Iconv.CAF 200 B",
|
||||
"MAIN.MAIN;GHC.IO.Handle.FD.CAF 33.89 KB",
|
||||
"MAIN.MAIN;Text.Printf.CAF 528 B",
|
||||
"MAIN.MAIN;Main.CAF:eta1_r6nI;Main.main;Main.check 2.00 MB",
|
||||
"MAIN.MAIN;Main.CAF:eta1_r6nI;Main.main 32 B",
|
||||
"MAIN.MAIN;Main.CAF:eta_r6nG 1.07 KB",
|
||||
"MAIN.MAIN;Main.CAF:io1 1.84 KB",
|
||||
"MAIN.MAIN;Main.CAF:lvl2_r6nH;Main.main;Main.main.long;Main.make 7.50 MB",
|
||||
"MAIN.MAIN;Main.CAF:lvl2_r6nH;Main.main;Main.main.long 32 B",
|
||||
"MAIN.MAIN;Main.CAF:lvl8_r6nP 520 B",
|
||||
"MAIN.MAIN;Main.CAF:main1 16 B",
|
||||
"MAIN.MAIN;Main.CAF:main11;Main.main;Main.main.c;Main.check 4.00 MB",
|
||||
"MAIN.MAIN;Main.CAF:main11;Main.main;Main.main.c 32 B",
|
||||
"MAIN.MAIN;Main.CAF:main12;Main.main;Main.main.c;Main.make 15.00 MB",
|
||||
"MAIN.MAIN;Main.CAF:main12;Main.main;Main.main.c 32 B",
|
||||
"MAIN.MAIN;Main.CAF:main7 880 B",
|
||||
"MAIN.MAIN;Main.CAF:main_maxN;Main.main;Main.main.maxN 32 B",
|
||||
"MAIN.MAIN;Main.CAF:main_stretchN;Main.main;Main.main.stretchN 32 B",
|
||||
"MAIN.MAIN;PROFILING.OVERHEAD_of 2.44 KB",
|
||||
"MAIN.MAIN;SYSTEM.SYSTEM 33.92 KB",
|
||||
"MAIN.MAIN;Main.main;Main.main.\\\\;Main.io 43.41 KB",
|
||||
"MAIN.MAIN;Main.main;Main.main.\\\\ 2.17 KB",
|
||||
"MAIN.MAIN;Main.main;Main.io 22.91 KB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a;Main.check 190.67 MB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a;Main.make 710.00 MB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.a 1.33 MB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.b;Main.check 190.67 MB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.b;Main.make 710.00 MB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth;Main.sumT;Main.sumT.b 1.33 MB",
|
||||
"MAIN.MAIN;Main.main;Main.main.vs;Main.depth 1.09 KB",
|
||||
"MAIN.MAIN 648 B",
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`importFromHaskell: indexToView 1`] = `0`;
|
||||
|
||||
exports[`importFromHaskell: profileGroup.name 1`] = `"binary-trees"`;
|
5
src/import/haskell.test.ts
Normal file
5
src/import/haskell.test.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import {checkProfileSnapshot} from '../lib/test-utils'
|
||||
|
||||
test('importFromHaskell', async () => {
|
||||
await checkProfileSnapshot('./sample/profiles/haskell/simple.prof')
|
||||
})
|
98
src/import/haskell.ts
Normal file
98
src/import/haskell.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import {ProfileGroup, FrameInfo, CallTreeProfileBuilder} from '../lib/profile'
|
||||
import {TimeFormatter, ByteFormatter} from '../lib/value-formatters'
|
||||
|
||||
// See https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html#json-profile-format
|
||||
// for information on the GHC profiler JSON output format.
|
||||
|
||||
interface CostCentre {
|
||||
id: number
|
||||
label: string
|
||||
module: string
|
||||
src_loc: string
|
||||
is_caf: boolean
|
||||
}
|
||||
|
||||
interface ProfileTree {
|
||||
id: number
|
||||
entries: number
|
||||
alloc: number
|
||||
ticks: number
|
||||
children: ProfileTree[]
|
||||
}
|
||||
|
||||
interface HaskellProfile {
|
||||
program: string
|
||||
arguments: string[]
|
||||
rts_arguments: string[]
|
||||
end_time: string
|
||||
initial_capabilities: number
|
||||
total_time: number
|
||||
total_ticks: number
|
||||
tick_interval: number
|
||||
total_alloc: number
|
||||
cost_centres: CostCentre[]
|
||||
profile: ProfileTree
|
||||
}
|
||||
|
||||
// The profiler already collapses recursion before output so using the JS stack here should be fine
|
||||
function addToProfile(
|
||||
tree: ProfileTree,
|
||||
startVal: number,
|
||||
profile: CallTreeProfileBuilder,
|
||||
infos: Map<number, FrameInfo>,
|
||||
attribute: (tree: ProfileTree) => number,
|
||||
): number {
|
||||
// If the expression never did anything we don't care about it
|
||||
if (tree.ticks === 0 && tree.entries === 0 && tree.alloc === 0 && tree.children.length === 0)
|
||||
return startVal
|
||||
|
||||
let curVal = startVal
|
||||
let frameInfo = infos.get(tree.id)!
|
||||
|
||||
profile.enterFrame(frameInfo, curVal)
|
||||
|
||||
for (let child of tree.children) {
|
||||
curVal = addToProfile(child, curVal, profile, infos, attribute)
|
||||
}
|
||||
|
||||
curVal += attribute(tree)
|
||||
|
||||
profile.leaveFrame(frameInfo, curVal)
|
||||
|
||||
return curVal
|
||||
}
|
||||
|
||||
export function importFromHaskell(haskellProfile: HaskellProfile): ProfileGroup {
|
||||
const idToFrameInfo = new Map<number, FrameInfo>()
|
||||
for (let centre of haskellProfile.cost_centres) {
|
||||
const frameInfo: FrameInfo = {
|
||||
key: centre.id,
|
||||
name: `${centre.module}.${centre.label}`,
|
||||
}
|
||||
|
||||
// Ignore things like <entire-module> and <no location info>
|
||||
if (!centre.src_loc.startsWith('<')) {
|
||||
// This also contains line and column information, but sometimes it contains ranges,
|
||||
// and in varying formats, so it's a better experience just to leave it as is
|
||||
frameInfo.file = centre.src_loc
|
||||
}
|
||||
|
||||
idToFrameInfo.set(centre.id, frameInfo)
|
||||
}
|
||||
|
||||
const timeProfile = new CallTreeProfileBuilder(haskellProfile.total_ticks)
|
||||
addToProfile(haskellProfile.profile, 0, timeProfile, idToFrameInfo, tree => tree.ticks)
|
||||
timeProfile.setValueFormatter(new TimeFormatter('milliseconds'))
|
||||
timeProfile.setName(`${haskellProfile.program} time`)
|
||||
|
||||
const allocProfile = new CallTreeProfileBuilder(haskellProfile.total_ticks)
|
||||
addToProfile(haskellProfile.profile, 0, allocProfile, idToFrameInfo, tree => tree.alloc)
|
||||
allocProfile.setValueFormatter(new ByteFormatter())
|
||||
allocProfile.setName(`${haskellProfile.program} allocation`)
|
||||
|
||||
return {
|
||||
name: haskellProfile.program,
|
||||
indexToView: 0,
|
||||
profiles: [timeProfile.build(), allocProfile.build()],
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ import {importFromFirefox} from './firefox'
|
||||
import {importSpeedscopeProfiles} from '../lib/file-format'
|
||||
import {importFromV8ProfLog} from './v8proflog'
|
||||
import {importFromLinuxPerf} from './linux-tools-perf'
|
||||
import {importFromHaskell} from './haskell'
|
||||
import {ProfileDataSource, TextProfileDataSource, MaybeCompressedDataReader} from './utils'
|
||||
import {importAsPprofProfile} from './pprof'
|
||||
import {decodeBase64} from '../lib/utils'
|
||||
@ -136,6 +137,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise<Profi
|
||||
} else if ('head' in parsed && 'selfSize' in parsed['head']) {
|
||||
console.log('Importing as Chrome Heap Profile')
|
||||
return toGroup(importFromChromeHeapProfile(JSON.parse(contents)))
|
||||
} else if ('rts_arguments' in parsed && 'initial_capabilities' in parsed) {
|
||||
console.log('Importing as Haskell GHC JSON Profile')
|
||||
return importFromHaskell(parsed)
|
||||
}
|
||||
} else {
|
||||
// Format is not JSON
|
||||
|
Loading…
Reference in New Issue
Block a user