Callgrind import format support (#331)
Implements import from the [callgrind format](https://www.valgrind.org/docs/manual/cl-format.html). This comes with a big caveat that the call graph information contained with callgrind formatted files don't uniquely define a flamegraph, so the generated flamegraph is a best-effort guess. Here's the comment from the top of the main file for the callgrind importer with an examplataion: ``` // https://www.valgrind.org/docs/manual/cl-format.html // // Larger example files can be found by searching on github: // https://github.com/search?q=cfn%3D&type=code // // Converting callgrind files into flamegraphs is challenging because callgrind // formatted profiles contain call graphs with weighted nodes and edges, and // such a weighted call graph does not uniquely define a flamegraph. // // Consider a program that looks like this: // // // example.js // function backup(read) { // if (read) { // read() // } else { // write() // } // } // // function start() { // backup(true) // } // // function end() { // backup(false) // } // // start() // end() // // Profiling this program might result in a profile that looks like the // following flame graph defined in Brendan Gregg's plaintext format: // // start;backup;read 4 // end;backup;write 4 // // When we convert this execution into a call-graph, we get the following: // // +------------------+ +---------------+ // | start (self: 0) | | end (self: 0) | // +------------------+ +---------------| // \ / // (total: 4) \ / (total: 4) // v v // +------------------+ // | backup (self: 0) | // +------------------+ // / \ // (total: 4) / \ (total: 4) // v v // +----------------+ +-----------------+ // | read (self: 4) | | write (self: 4) | // +----------------+ +-----------------+ // // In the process of the conversion, we've lost information about the ratio of // time spent in read v.s. write in the start call v.s. the end call. The // following flame graph would yield the exact same call-graph, and therefore // the exact sample call-grind formatted profile: // // start;backup;read 3 // start;backup;write 1 // end;backup;read 1 // end;backup;write 3 // // This is unfortunate, since it means we can't produce a flamegraph that isn't // potentially lying about the what the actual execution behavior was. To // produce a flamegraph at all from the call graph representation, we have to // decide how much weight each sub-call should have. Given that we know the // total weight of each node, we'll make the incorrect assumption that every // invocation of a function will have the average distribution of costs among // the sub-function invocations. In the example given, this means we assume that // every invocation of backup() is assumed to spend half its time in read() and // half its time in write(). // // So the flamegraph we'll produce from the given call-graph will actually be: // // start;backup;read 2 // start;backup;write 2 // end;backup;read 2 // end;backup;write 2 // // A particularly bad consequence is that the resulting flamegraph will suggest // that there was at some point a call stack that looked like // strat;backup;write, even though that never happened in the real program // execution. ``` Fixes #18
This commit is contained in:
24
sample/profiles/callgrind/callgrind.example.log
Normal file
24
sample/profiles/callgrind/callgrind.example.log
Normal file
@@ -0,0 +1,24 @@
|
||||
# callgrind format
|
||||
events: Instructions
|
||||
|
||||
fl=file1.c
|
||||
fn=main
|
||||
16 20
|
||||
cfn=func1
|
||||
calls=1 50
|
||||
16 400
|
||||
cfi=file2.c
|
||||
cfn=func2
|
||||
calls=3 20
|
||||
16 400
|
||||
|
||||
fn=func1
|
||||
51 100
|
||||
cfi=file2.c
|
||||
cfn=func2
|
||||
calls=2 20
|
||||
51 300
|
||||
|
||||
fl=file2.c
|
||||
fn=func2
|
||||
20 700
|
||||
29
sample/profiles/callgrind/callgrind.multiple-event-types.log
Normal file
29
sample/profiles/callgrind/callgrind.multiple-event-types.log
Normal file
@@ -0,0 +1,29 @@
|
||||
version: 1
|
||||
creator: xdebug 3.0.2 (PHP 7.4.14)
|
||||
cmd: /var/www/html/index.php
|
||||
part: 1
|
||||
positions: line
|
||||
|
||||
events: Time_(10ns) Memory_(bytes)
|
||||
|
||||
fl=(1) file1.c
|
||||
fn=(1) main
|
||||
16 20 15000
|
||||
cfn=(2) func1
|
||||
calls=1 50
|
||||
16 400 20000
|
||||
cfi=(2) file2.c
|
||||
cfn=(3) func2
|
||||
calls=3 51
|
||||
16 400 3000
|
||||
|
||||
fn=(2)
|
||||
51 100 4000
|
||||
cfi=(2)
|
||||
cfn=(3)
|
||||
calls=2 20
|
||||
51 300 5000
|
||||
|
||||
fl=(2)
|
||||
fn=(3)
|
||||
20 700 6000
|
||||
24
sample/profiles/callgrind/callgrind.name-compression.log
Normal file
24
sample/profiles/callgrind/callgrind.name-compression.log
Normal file
@@ -0,0 +1,24 @@
|
||||
# callgrind format
|
||||
events: Instructions
|
||||
|
||||
fl=(1) file1.c
|
||||
fn=(1) main
|
||||
16 20
|
||||
cfn=(2) func1
|
||||
calls=1 50
|
||||
16 400
|
||||
cfi=(2) file2.c
|
||||
cfn=(3) func2
|
||||
calls=3 20
|
||||
16 400
|
||||
|
||||
fn=(2)
|
||||
51 100
|
||||
cfi=(2)
|
||||
cfn=(3)
|
||||
calls=2 20
|
||||
51 300
|
||||
|
||||
fl=(2)
|
||||
fn=(3)
|
||||
20 700
|
||||
Reference in New Issue
Block a user