ref:main
# Read-path benchmark — source of truth for the perf effort
Generated by `mix exgo.bench` (see moduledoc) via `bench/run_all.sh`.
Repo: a 134,921-object packed mirror. Median of 3 runs (clone: 1 run, 60s
per-op cap). Numbers in **ms**. `>N` = exceeded the cap (lower bound).
| operation | native git | FS (local) | FS on CephFS | S3 / MinIO | S3 / Ceph RGW |
| --- | --- | --- | --- | --- | --- |
| resolve HEAD | 4.7 | 0.1 | 7.4 | 1.5 | 12.1 |
| read 1 commit | 4.6 | 0.6 | 9.4 | 4.4 | 6.5 |
| read 1 blob | 5.1 | 0.7 | 5.4 | 5.6 | 7.9 |
| open file by path | 5.6 | 0.9 | 13.9 | 8.0 | 9.9 |
| list root tree | 4.7 | 0.4 | 7.8 | 5.5 | 7.1 |
| tree + blob sizes | 5.3 | 5.9 | 106.0 | 56.3 | 64.6 |
| commit log page (50) | 6.3 | 2.6 | 34.3 | 21.2 | 25.4 |
| full history walk | 7.7 | 2720.3 | 17294.2 | 2841.0 | 2825.4 |
| diff two commits | 17.4 | 327.4 | 1547.5 | 489.3 | 549.4 |
| ahead/behind | 5.4 | 18.7 | 51.3 | 20.0 | 19.3 |
| merge-base | 4.7 | 4.4 | 609.4 | 35.6 | 44.6 |
| clone (read all reachable) | 178.2 | >6.0e4 | >6.0e4 | >6.0e4 | >6.0e4 |
## Reading this table
- **native git** is the reference ("what's achievable"). It carries a ~5-15 ms
floor = git CLI process-spawn per op (sub-ms work on cheap ops), so the
walk/clone gaps are *understated*.
- **Ceph** (RGW + CephFS) ran as an emulated-amd64 single-node demo — directional,
and its idle CPU adds noise to all columns in a shared run.
- All ExGitObjectstore columns use the ranged reader (ex_git_objectstore PR #44).
## Gaps to close (vs native git) — the perf backlog
- **clone >150x** (timed out >60s vs ~0.2-0.4s): no pack reuse; reachable walk
decodes every object.
- **full history walk ~270x** (and worse on CephFS/FUSE): per-commit object read
with delta re-resolution; no commit-graph for topology.
- **diff ~35x**, **tree+blob-sizes 3-11x**, **merge-base** amplified on slow backends.
- Common cause: per-object zlib inflate + delta-base re-resolution with **no
cross-read object/delta-base cache**, and **no commit-graph**. Point reads are
already at parity — the gaps are all in multi-object walk/decode paths.