Micro-benchmarking in OCaml
It is instructive to understand time and space requirements of functions we write and micro-benchmarking tools of a language helps us accomplish this task. Ocaml has a library called Core_bench for this task. Let's see how it works.
In the example code below, we do three things. First, we open two modules -
Core_bench. Next, we create two functions that we want to benchmark - sum of n natural numbers and factorial. Third part is where the benchmarking is actually performed.
Bench.make_command takes a list of tests as its argumen. This is wrapped inside
Command.run, which why we needed the
Core module as well. Each test is created using
Bench.Test.create function which takes a named argument,
name, and an anonymous function wrapped inside parenthesis. The body of the function has
ignore followed by our test function.
open Core open Core_bench let rec sumn n = if n = 0 then 0 else n + sumn (n-1) let rec fact n = if n = 0 then 1 else n * fact (n-1) let () = Command.run (Bench.make_command [ Bench.Test.create ~name:"sumn" (fun () -> ignore (sumn 10)); Bench.Test.create ~name:"fact" (fun () -> ignore (fact 10));])
When we compile and run the above code, each function will be run for 10 seconds and results will be displayed in a nice table in console:
Estimated testing time 20s (2 benchmarks x 10s). Change using '-quota'. ┌──────┬──────────┬────────────┐ │ Name │ Time/Run │ Percentage │ ├──────┼──────────┼────────────┤ │ sumn │ 19.61ns │ 77.80% │ │ fact │ 25.20ns │ 100.00% │ └──────┴──────────┴────────────┘
The table above shows that sumn took about 20 ns to finish while fact took about 25. Thus sumn ran about 22% faster than factorial.
This is just the bare minimum to get started. There is an interesting design discussion about the tool. Based on the memory consumed, it can also show columns with memory used in minor and major heaps, which is the concept used by OCaml's garbage collector.