I wanted to profile some programs using perf, and I observed some strange behaviour on OCaml 5. Switching to OCaml 4, the number seemed more reasonable.
I would tend to say that the reason is that time spent in the GC is not put as a child of the correct function perf since 5.0, seeing the output below.
Here is a somewhat minimal example:
(* test.ml *)
let l = ref []
let rec lots_of_allocs i =
if i = 0 then ()
else (
for _ = 0 to 99999 do
let i = ref 0 in
i := !i + 1;
i := !i - 1;
l := !i :: !l
done;
l := [];
lots_of_allocs (i - 1))
let rec lots_of_nothing i =
if i = 0 then ()
else (
for _ = 0 to 100000000 do
()
done;
lots_of_nothing (i - 1))
let measure f =
let t =
let start = Unix.gettimeofday () in
let _ = f () in
let end_ = Unix.gettimeofday () in
end_ -. start
in
Format.printf "Took %f seconds.\n%!" t
let () =
print_endline "Starting lots_of_nothing";
(measure @@ fun () -> lots_of_nothing 100);
print_endline "Starting a lots_of_allocs";
(measure @@ fun () -> lots_of_allocs 1000);
print_endline "finished"
When I run this file, I have some information about the time spent in each function, lots_of_allocs and lots_of_nothing:
$ ocamlopt --version
5.0.0
$ ocamlopt -I +unix -g unix.cmxa test.ml
$ perf record --call-graph dwarf ./a.out
Starting lots_of_nothing
Took 2.361002 seconds.
Starting a lots_of_allocs
Took 1.551887 seconds.
finished
[ perf record: Woken up 538 times to write data ]
[ perf record: Captured and wrote 134.438 MB perf.data (16701 samples) ]
However, if I ask perf about the time spent in each function, I get a result which does not match the measured time:
$ perf report
[...]
- 64.97% 0.00% a.out a.out [.] Test.entry
Test.entry
- Test.measure_276
61.30% Test.lots_of_nothing_273
3.67% Test.lots_of_allocs_269
[...]
So, only 3.67% on lots_of_allocs, while it takes 1.55 seconds (compared to 61.30% for the 2.3 seconds of lots_of_nothing).
After that, I tried the same thing using ocaml 4.14:
$ ocamlopt --version
4.14.1
$ ocamlopt -I +unix -g unix.cmxa test.ml
$ perf record --call-graph dwarf ./a.out
Starting lots_of_nothing
Took 2.540385 seconds.
Starting a lots_of_allocs
Took 2.139729 seconds.
finished
[ perf record: Woken up 596 times to write data ]
[ perf record: Captured and wrote 149.053 MB perf.data (18499 samples) ]
Then, perf reports:
$ perf report
[...]
- 94.31% 0.00% a.out a.out [.] Test.entry
Test.entry
- Test.measure_275
59.78% Test.lots_of_nothing_272
- 34.53% Test.lots_of_allocs_268
+ 29.47% caml_call_gc
2.30% caml_modify
[...]
The time is now correctly counted, and there are children to the lots_of_allocs function. One of them is the gc, and seems to account for the missing time in OCaml 5...
I wanted to profile some programs using
perf, and I observed some strange behaviour on OCaml 5. Switching to OCaml 4, the number seemed more reasonable.I would tend to say that the reason is that time spent in the GC is not put as a child of the correct function perf since 5.0, seeing the output below.
Here is a somewhat minimal example:
When I run this file, I have some information about the time spent in each function,
lots_of_allocsandlots_of_nothing:$ ocamlopt --version 5.0.0 $ ocamlopt -I +unix -g unix.cmxa test.ml $ perf record --call-graph dwarf ./a.out Starting lots_of_nothing Took 2.361002 seconds. Starting a lots_of_allocs Took 1.551887 seconds. finished [ perf record: Woken up 538 times to write data ] [ perf record: Captured and wrote 134.438 MB perf.data (16701 samples) ]However, if I ask
perfabout the time spent in each function, I get a result which does not match the measured time:$ perf report [...] - 64.97% 0.00% a.out a.out [.] Test.entry Test.entry - Test.measure_276 61.30% Test.lots_of_nothing_273 3.67% Test.lots_of_allocs_269 [...]So, only 3.67% on
lots_of_allocs, while it takes 1.55 seconds (compared to 61.30% for the 2.3 seconds oflots_of_nothing).After that, I tried the same thing using ocaml 4.14:
$ ocamlopt --version 4.14.1 $ ocamlopt -I +unix -g unix.cmxa test.ml $ perf record --call-graph dwarf ./a.out Starting lots_of_nothing Took 2.540385 seconds. Starting a lots_of_allocs Took 2.139729 seconds. finished [ perf record: Woken up 596 times to write data ] [ perf record: Captured and wrote 149.053 MB perf.data (18499 samples) ]Then,
perfreports:The time is now correctly counted, and there are children to the
lots_of_allocsfunction. One of them is the gc, and seems to account for the missing time in OCaml 5...