Persistent store with Git semantics: lazy reads, delayed writes, content-addressing
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add --cache flag to benchmarks for LRU cache testing

Runners accept an optional ~cache parameter that wraps the backend
with Backend.cached. The main CLI exposes --cache N to set the
capacity. Names include "+cache" suffix when cache is active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+50 -34
+18 -10
bench/bench_irmin4.ml
··· 8 8 Measures write throughput and commit overhead. *) 9 9 let scenario_commits ~name ~(backend : Hash.sha1 Backend.t) 10 10 (conf : Bench_common.config) = 11 - let store = Store.Git.create ~backend in 11 + let store = Store.Git.create ~backend () in 12 12 let paths = 13 13 Array.init (conf.tree_add + 1) (Bench_common.path ~depth:conf.depth) 14 14 in ··· 69 69 Populates a tree, then reads random entries. Measures read throughput. *) 70 70 let scenario_reads ~name ~(backend : Hash.sha1 Backend.t) 71 71 (conf : Bench_common.config) = 72 - let store = Store.Git.create ~backend in 72 + let store = Store.Git.create ~backend () in 73 73 let paths = 74 74 Array.init (conf.tree_add + 1) (Bench_common.path ~depth:conf.depth) 75 75 in ··· 116 116 Measures overhead of small updates on a large tree. *) 117 117 let scenario_incremental ~name ~(backend : Hash.sha1 Backend.t) 118 118 (conf : Bench_common.config) = 119 - let store = Store.Git.create ~backend in 119 + let store = Store.Git.create ~backend () in 120 120 let paths = 121 121 Array.init (conf.tree_add + 1) (Bench_common.path ~depth:conf.depth) 122 122 in ··· 175 175 let scenario_large_values ~name ~(backend : Hash.sha1 Backend.t) 176 176 (conf : Bench_common.config) = 177 177 let large_size = 10_000 in 178 - let store = Store.Git.create ~backend in 178 + let store = Store.Git.create ~backend () in 179 179 let npaths = min conf.tree_add 200 in 180 180 let paths = 181 181 Array.init (npaths + 1) (Bench_common.path ~depth:conf.depth) ··· 298 298 299 299 (** {1 Backend runners} *) 300 300 301 - let run_all_memory conf = 302 - let name = "Irmin4 (memory)" in 303 - let mk () = Backend.Memory.create_sha1 () in 301 + let run_all_memory ?(cache = 0) conf = 302 + let suffix = if cache > 0 then "+cache" else "" in 303 + let name = "Irmini" ^ suffix ^ " (memory)" in 304 + let mk () = 305 + let b = Backend.Memory.create_sha1 () in 306 + if cache > 0 then Backend.cached ~capacity:cache b else b 307 + in 304 308 [ 305 309 scenario_commits ~name ~backend:(mk ()) conf; 306 310 scenario_reads ~name ~backend:(mk ()) conf; ··· 308 312 scenario_large_values ~name ~backend:(mk ()) conf; 309 313 ] 310 314 311 - let run_all_disk ~sw ~env root conf = 312 - let name = "Irmin4 (disk)" in 313 - let mk () = Backend.Disk.create_sha1 ~sw root in 315 + let run_all_disk ?(cache = 0) ~sw ~env root conf = 316 + let suffix = if cache > 0 then "+cache" else "" in 317 + let name = "Irmini" ^ suffix ^ " (disk)" in 318 + let mk () = 319 + let b = Backend.Disk.create_sha1 ~sw root in 320 + if cache > 0 then Backend.cached ~capacity:cache b else b 321 + in 314 322 let run_one f = 315 323 let backend = mk () in 316 324 Fun.protect ~finally:(fun () -> backend.close ()) (fun () -> f ~backend)
+7 -3
bench/bench_irmin4_lavyek.ml
··· 3 3 Each scenario gets a fresh Lavyek store in a separate subdirectory 4 4 to avoid WAL replay issues between runs. *) 5 5 6 - let run_all ~sw ~env root (conf : Bench_common.config) = 7 - let name = "Irmin4 (lavyek)" in 6 + let run_all ?(cache = 0) ~sw ~env root (conf : Bench_common.config) = 7 + let suffix = if cache > 0 then "+cache" else "" in 8 + let name = "Irmini" ^ suffix ^ " (lavyek)" in 8 9 let n = ref 0 in 9 10 let run_one f = 10 11 incr n; 11 12 let subdir = Eio.Path.(root / Printf.sprintf "scenario_%d" !n) in 12 - let backend = Backend_lavyek.create ~sw subdir in 13 + let b = Backend_lavyek.create ~sw subdir in 14 + let backend = 15 + if cache > 0 then Irmin.Backend.cached ~capacity:cache b else b 16 + in 13 17 Fun.protect 14 18 ~finally:(fun () -> backend.Irmin.Backend.close ()) 15 19 (fun () -> f ~backend)
+25 -21
bench/bench_irmin4_main.ml
··· 1 - (** Irmin4 benchmark runner. 1 + (** Irmini benchmark runner. 2 2 3 - Benchmarks Irmin4 with memory, disk, and lavyek backends across 3 + Benchmarks Irmini with memory, disk, and lavyek backends across 4 4 multiple scenarios: commits, reads, incremental updates, large values. 5 + Optionally runs with LRU cache enabled. 5 6 6 7 Usage: bench_irmin4_main [--ncommits N] [--tree-add N] [--depth N] 7 8 [--nreads N] [--value-size N] 8 - [--skip-lavyek] [--skip-disk] *) 9 + [--skip-lavyek] [--skip-disk] 10 + [--cache N] *) 9 11 10 12 let () = 11 13 let ncommits = ref 100 in ··· 15 17 let value_size = ref 100 in 16 18 let skip_lavyek = ref false in 17 19 let skip_disk = ref false in 20 + let cache = ref 0 in 18 21 Arg.parse 19 22 [ 20 23 ("--ncommits", Arg.Set_int ncommits, "Number of commits (default: 100)"); ··· 27 30 "Size of values in bytes (default: 100)"); 28 31 ("--skip-lavyek", Arg.Set skip_lavyek, "Skip Lavyek backend benchmark"); 29 32 ("--skip-disk", Arg.Set skip_disk, "Skip disk backend benchmark"); 33 + ("--cache", Arg.Set_int cache, 34 + "LRU cache capacity (default: 0 = no cache)"); 30 35 ] 31 36 (fun _ -> ()) 32 - "bench_irmin4 - Irmin4 performance benchmarks"; 37 + "bench_irmin4 - Irmini performance benchmarks"; 33 38 let conf : Bench_common.config = 34 39 { 35 40 ncommits = !ncommits; ··· 39 44 value_size = !value_size; 40 45 } 41 46 in 47 + let cache = !cache in 42 48 Format.printf 43 49 "Configuration: %d commits, %d adds/commit, depth %d, %d reads, \ 44 - %d-byte values@.@." 45 - conf.ncommits conf.tree_add conf.depth conf.nreads conf.value_size; 50 + %d-byte values%s@.@." 51 + conf.ncommits conf.tree_add conf.depth conf.nreads conf.value_size 52 + (if cache > 0 then Printf.sprintf ", cache=%d" cache else ""); 46 53 Eio_main.run @@ fun env -> 47 54 let cwd = Eio.Stdenv.cwd env in 48 55 let results = ref [] in ··· 56 63 in 57 64 (try rm path with _ -> ()) 58 65 in 59 - (* 1. Irmin4 memory *) 60 - Format.printf "--- Irmin4 (memory) ---@.@."; 61 - let rs = Bench_irmin4.run_all_memory conf in 62 - List.iter (fun r -> Format.printf "%a@.@." Bench_common.pp_result r) rs; 63 - results := rs @ !results; 64 - (* 2. Irmin4 disk *) 66 + let run name rs = 67 + Format.printf "--- %s ---@.@." name; 68 + List.iter (fun r -> Format.printf "%a@.@." Bench_common.pp_result r) rs; 69 + results := rs @ !results 70 + in 71 + (* 1. Irmini memory *) 72 + run "Irmini (memory)" (Bench_irmin4.run_all_memory ~cache conf); 73 + (* 2. Irmini disk *) 65 74 if not !skip_disk then begin 66 - Format.printf "--- Irmin4 (disk) ---@.@."; 67 75 Eio.Switch.run @@ fun sw -> 68 76 let root = Eio.Path.(cwd / "_build/_bench_disk") in 69 77 rm_rf root; 70 - let rs = Bench_irmin4.run_all_disk ~sw ~env root conf in 71 - List.iter (fun r -> Format.printf "%a@.@." Bench_common.pp_result r) rs; 72 - results := rs @ !results 78 + run "Irmini (disk)" (Bench_irmin4.run_all_disk ~cache ~sw ~env root conf) 73 79 end; 74 - (* 3. Irmin4 + Lavyek *) 80 + (* 3. Irmini + Lavyek *) 75 81 if not !skip_lavyek then begin 76 - Format.printf "--- Irmin4 (lavyek) ---@.@."; 77 82 Eio.Switch.run @@ fun sw -> 78 83 let root = Eio.Path.(cwd / "_build/_bench_lavyek") in 79 84 rm_rf root; 80 - let rs = Bench_irmin4_lavyek.run_all ~sw ~env root conf in 81 - List.iter (fun r -> Format.printf "%a@.@." Bench_common.pp_result r) rs; 82 - results := rs @ !results 85 + run "Irmini (lavyek)" 86 + (Bench_irmin4_lavyek.run_all ~cache ~sw ~env root conf) 83 87 end; 84 88 (* Summary *) 85 89 Bench_common.pp_comparison Format.std_formatter (List.rev !results)