A zero-dependency, single-file benchmarking library for OCaml
  • OCaml 99.1%
  • Dune 0.9%
Find a file
2025-08-10 11:44:40 -05:00
example Initial commit 2025-08-10 11:44:40 -05:00
lib Initial commit 2025-08-10 11:44:40 -05:00
.gitignore Initial commit 2025-08-10 11:44:40 -05:00
.ocamlformat Initial commit 2025-08-10 11:44:40 -05:00
dune-project Initial commit 2025-08-10 11:44:40 -05:00
LICENSE Initial commit 2025-08-10 11:44:40 -05:00
README.md Initial commit 2025-08-10 11:44:40 -05:00
ubench.opam Initial commit 2025-08-10 11:44:40 -05:00

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.ml and ubench.mli to 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_addition
  • strings/concat
  • strings/length
  • lists/operations/map
  • lists/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