# Profiling

Gerbil ships with a basic profiler tool, `gerbil prof` or just
`gxprof`. The tool can profile dynamically compiled executable
modules, by running them with an interrupt handler that samples the
current continuation on every scheduler heartbeat.

Once a profile sample file has been generated by running `gxprof` with
your module, you can analyze the samples for some (hopefully)
insightful statistics.

## Invocation

```shell
$ gerbil prof -h
gxprof: The Gerbil profiler

Usage: gxprof [option ...] [<module>] <module-args> ...

Options:
 -o --output <output>             gxprof output file [default: gxprof.out]
 --heartbeat  <heartbeat>         heartbeat interval for sampling, in seconds [default: .001]
 -h --help                        display help

Arguments:
 module                           dynamic executable module to run; analyze an existing output file if omitted [default: #f]
 module-args                      arguments to pass to the executable module's main
```

So basically `gxprof :your/executable-module arg ...` will run the
main function in `:your/executable-module` with the given arguments. The function
is run to completion, at which point the profiler writes the captured
continuation samples in gxprof.out in the current directory.

The contents of the file is a list of lists that contain the names of
the continuation creator for each frame in the captured
continuations. You can process the samples to extract detailed
profiling statistics.

You can then analyze the samples by rerunning `gxprof` without arguments.

## Example

Here is an example:
```shell
$ gxc -O json-benchmark.ss
$ gxprof :std/text/json/json-benchmark bio ~/Downloads/large-file.json
(time (std/text/json/json-benchmark#call-with-buffered-reader _file126_ std/text/json/api#read-json))
    0.595805 secs real time
    0.582223 secs cpu time (0.498561 user, 0.083662 system)
    18 collections accounting for 0.239713 secs real time (0.238992 user, 0.000703 system)
    1413985192 bytes allocated
    82594 minor faults
    no major faults
    1555767072 cpu cycles
(time (std/text/json/json-benchmark#call-with-buffered-writer _tmp130_ (lambda (_g131133_) (std/text/json/api#write-json__% _object128_ _g131133_))))
    0.246521 secs real time
    0.246516 secs cpu time (0.234621 user, 0.011895 system)
    no collections
    194321304 bytes allocated
    2964 minor faults
    no major faults
    643710478 cpu cycles

$ gxprof
... analyzing gxprof.out
Top Continuation Samples
------------------------
std/text/json/input#read-json-hash/buffer: 61 [36.970%]
std/text/json/output#write-json-string/buffer: 42 [25.455%]
std/text/json/input#read-json-hash-key/buffer: 17 [10.303%]
std/text/json/input#read-json-string/buffer: 15 [9.091%]
std/text/json/output#write-json-alist/buffer: 7 [4.242%]
std/sort#list-merge-sort: 6 [3.636%]
std/io/file#input-file-io::read: 3 [1.818%]
##table-foldl: 2 [1.212%]
std/text/json/output#write-json-list/buffer: 2 [1.212%]
std/io/file#output-file-io::write: 2 [1.212%]
##list->string: 2 [1.212%]
std/text/json/json-benchmark#benchmark-stdio-bio: 1 [0.606%]
std/text/json/input#read-json-list-next/buffer: 1 [0.606%]
std/text/json/input#read-json-object/buffer: 1 [0.606%]
std/text/json/output#write-json-hash/buffer: 1 [0.606%]
##string->number-slow-path: 1 [0.606%]
std/text/json/input#read-json-number/buffer: 1 [0.606%]

Call Graph Samples
------------------
##dynamic-wind: 392 [237.576%]
##dynamic-env-bind: 392 [237.576%]
std/text/json/input#read-json-hash/buffer: 349 [211.515%]
std/text/json/output#write-json-alist/buffer: 195 [118.182%]
##kernel-handlers: 165 [100.000%]
std/text/json/json-benchmark#benchmark-stdio-bio: 165 [100.000%]
##exec-stats: 164 [99.394%]
##time-thunk: 164 [99.394%]
std/text/json/input#read-json-list/buffer: 114 [69.091%]
std/text/json/input#read-json-list-next/buffer: 114 [69.091%]
std/text/json/json-benchmark#call-with-buffered-reader: 102 [61.818%]
std/sort#list-merge-sort: 89 [53.939%]
std/text/json/output#write-json-list/buffer: 74 [44.848%]
std/text/json/output#write-json-string/buffer: 67 [40.606%]
std/text/json/input#read-json-hash-keybuffer: 23 [13.939%]
std/text/json/input#read-json-string/buffer: 18 [10.909%]
std/text/json/output#write-json-hash/buffer: 9 [5.455%]
std/io/bio/util#&BufferedReader-read-char: 3 [1.818%]
std/io/file#input-file-io::read: 3 [1.818%]
##table-foldl: 2 [1.212%]
std/io/bio/output#bio-write-u8: 2 [1.212%]
std/io/file#output-file-io::write: 2 [1.212%]
##list->string: 2 [1.212%]
##string->number-slow-path: 2 [1.212%]
std/text/json/input#read-json-number/buffer: 2 [1.212%]
std/io/bio/util#&BufferedWriter-write-string__%: 1 [0.606%]
std/text/json/input#read-json-object/buffer: 1 [0.606%]
vyzo@dellicious:~/gerbil/src/std/text/json$
```

If you want to hide kernel continuations from the sample (they are not
usually very intesting), you can do so with the `-k` analysis options:
```shell
$ gxprof -k
... analyzing gxprof.out
Top Continuation Samples
------------------------
std/text/json/input#read-json-hash/buffer: 61 [36.970%]
std/text/json/output#write-json-string/buffer: 42 [25.455%]
std/text/json/input#read-json-hash-keybuffer: 17 [10.303%]
std/text/json/input#read-json-string/buffer: 15 [9.091%]
std/text/json/output#write-json-alist/buffer: 7 [4.242%]
std/sort#list-merge-sort: 6 [3.636%]
std/io/file#input-file-io::read: 3 [1.818%]
##list->string: 2 [1.212%]
##table-foldl: 2 [1.212%]
std/text/json/output#write-json-list/buffer: 2 [1.212%]
std/io/file#output-file-io::write: 2 [1.212%]
std/text/json/input#read-json-object/buffer: 1 [0.606%]
std/text/json/input#read-json-list-next/buffer: 1 [0.606%]
std/text/json/input#read-json-number/buffer: 1 [0.606%]
##string->number-slow-path: 1 [0.606%]
std/text/json/output#write-json-hash/buffer: 1 [0.606%]
std/text/json/json-benchmark#benchmark-stdio-bio: 1 [0.606%]

Call Graph Samples
------------------
std/text/json/input#read-json-hash/buffer: 349 [211.515%]
std/text/json/output#write-json-alist/buffer: 195 [118.182%]
std/text/json/json-benchmark#benchmark-stdio-bio: 165 [100.000%]
##exec-stats: 164 [99.394%]
##time-thunk: 164 [99.394%]
std/text/json/input#read-json-list-next/buffer: 114 [69.091%]
std/text/json/input#read-json-list/buffer: 114 [69.091%]
std/text/json/json-benchmark#call-with-buffered-reader: 102 [61.818%]
std/sort#list-merge-sort: 89 [53.939%]
std/text/json/output#write-json-list/buffer: 74 [44.848%]
std/text/json/output#write-json-string/buffer: 67 [40.606%]
std/text/json/input#read-json-hash-keybuffer: 23 [13.939%]
std/text/json/input#read-json-string/buffer: 18 [10.909%]
std/text/json/output#write-json-hash/buffer: 9 [5.455%]
std/io/file#input-file-io::read: 3 [1.818%]
std/io/bio/util#&BufferedReader-read-char: 3 [1.818%]
##list->string: 2 [1.212%]
std/text/json/input#read-json-number/buffer: 2 [1.212%]
##table-foldl: 2 [1.212%]
std/io/bio/output#bio-write-u8: 2 [1.212%]
std/io/file#output-file-io::write: 2 [1.212%]
##string->number-slow-path: 2 [1.212%]
std/text/json/input#read-json-object/buffer: 1 [0.606%]
std/io/bio/util#&BufferedWriter-write-string__%: 1 [0.606%]
```

Also note, that in the call graph samples, some procedures may have
more than 100% coverage. This is _not a bug_; a procedure may appear
multiple times within the same continuation sample because of a
recursive call.
