A zero-dependency, single-file benchmarking library for OCaml
- OCaml 99.1%
- Dune 0.9%
| example | ||
| lib | ||
| .gitignore | ||
| .ocamlformat | ||
| dune-project | ||
| LICENSE | ||
| README.md | ||
| ubench.opam | ||
ubench
A zero-dependency, single-file benchmarking library for OCaml
Simple, fast, and accurate benchmarking with a clean API. No external dependencies - just copy the file and start benchmarking.
Features
- 🚀 Zero dependencies - Only uses OCaml's standard library
- 📦 Single file - Copy
ubench.mlandubench.mlito your project - 🎯 Accurate measurements - Statistical analysis with confidence intervals
- 🌳 Hierarchical organization - Group related benchmarks with automatic name prefixing
- ⚡ Smart sampling - Geometric scaling with variance-based convergence
- 📊 Multiple output formats - Pretty tables, JSON, and CSV
- 🔧 Ergonomic API - Concise syntax with automatic result handling
Quick Start
open Ubench
let () =
let benchmarks = [
bench "list_map" (fun () -> List.map (fun x -> x * 2) [1; 2; 3; 4; 5]);
bench "array_init" (fun () -> Array.init 100 (fun i -> i * i));
bench "string_concat" (fun () -> "hello" ^ " " ^ "world");
] in
let _ = run benchmarks in ()
Installation
Option 1: Copy the files
Simply copy lib/ubench.ml and lib/ubench.mli to your project.
Option 2: Install with opam
opam install ubench
API Overview
Core Functions
(* Create a simple benchmark *)
val bench : string -> (unit -> 'a) -> benchmark
(* Group related benchmarks *)
val group : string -> benchmark list -> benchmark
(* Parameterized benchmarks *)
val bench_param : string -> (param:'a -> 'b) -> params:(string * 'a) list -> benchmark list
(* Benchmark with setup/teardown *)
val bench_with_setup : string -> setup:(unit -> 'a) -> teardown:('a -> unit) -> f:('a -> 'b) -> benchmark
(* Run benchmarks *)
val run : ?config:Config.t -> ?output_format:output_format -> ?verbose:bool -> benchmark list -> analysis_result list
Examples
Hierarchical Groups
Organize benchmarks into logical groups with automatic name prefixing:
let benchmarks = [
bench "simple_addition" (fun () -> 1 + 1);
group "strings" [
bench "concat" (fun () -> "hello" ^ " world");
bench "length" (fun () -> String.length "hello");
bench "uppercase" (fun () -> String.uppercase_ascii "hello");
];
group "lists" [
group "operations" [
bench "map" (fun () -> List.map (fun x -> x * 2) [1; 2; 3]);
bench "filter" (fun () -> List.filter (fun x -> x > 2) [1; 2; 3]);
];
group "sizes" [
bench "small" (fun () -> List.length [1; 2; 3]);
bench "large" (fun () -> List.length (List.init 1000 Fun.id));
];
];
]
This creates benchmarks with hierarchical names:
simple_additionstrings/concatstrings/lengthlists/operations/maplists/sizes/large
Parameterized Benchmarks
Test performance across different input sizes:
group "arrays" (
bench_param "init"
~params:[("10", 10); ("100", 100); ("1000", 1000)]
(fun ~param -> Array.init param (fun i -> i * i))
)
Setup and Teardown
Manage resources properly:
bench_with_setup "hashtbl_operations"
~setup:(fun () ->
let tbl = Hashtbl.create 1000 in
for i = 0 to 999 do
Hashtbl.add tbl i (string_of_int i)
done;
tbl)
~teardown:(fun _ -> ())
~f:(fun tbl ->
for i = 0 to 99 do
ignore (Hashtbl.find_opt tbl (Random.int 1000))
done)
Configuration
let config =
Config.default
|> Config.time_limit 5.0 (* Run for 5 seconds *)
|> Config.warmup 10 (* 10 warmup iterations *)
|> Config.gc_stabilization true (* Stabilize GC between measurements *)
in
let _ = run ~config benchmarks in ()
Output Formats
(* Pretty table (default) *)
let _ = run benchmarks in ()
(* JSON output *)
let _ = run ~output_format:JSON benchmarks in ()
(* CSV output *)
let _ = run ~output_format:CSV benchmarks in ()
(* Save results to files *)
let results = run_silent benchmarks in
save_results_json "results.json" results;
save_results_csv "results.csv" results
Advanced Features
Statistical Analysis
- Bootstrap confidence intervals for robust statistics
- Ordinary least squares regression with R² and adjusted R²
- Overhead estimation using constant predictors
- Variance-based convergence for adaptive sampling
GC Measurements
- Tracks allocations (minor/major/promoted words)
- Monitors GC collections and compactions
- Optional GC stabilization between measurements
Performance Metrics
- CPU time (user + system)
- Wall clock time
- Estimated CPU cycles
- Memory allocations
- GC statistics
License
ISC License - See LICENSE file for details