OXYGENHUB
# 07eb99be126e oxygen / docs / benchmarks.md
3.1 KiB · Markdown · last changed Benchmark harness and first numbers 1 month ago renderedsource blame history raw
1
# Benchmarks
2
3
The harness is `crates/oxy-core/tests/bench.rs` (spec §25). It builds a
4
repository through the library, one commit at a time, then times the
5
everyday operations against thresholds:
6
7
    OXY_BENCH_DIR=~/.cache/oxy-bench \
8
      cargo test --release -p oxy-core --test bench -- --ignored --nocapture
9
10
`OXY_BENCH_FILES` (default 10 000) and `OXY_BENCH_CHANGES` (default
11
5 000) set the size. The data lands under `OXY_BENCH_DIR`; `/tmp` is often
12
a RAM disk, which hides the cost of `fsync`, so measure on a real disk.
13
14
## 2026-09-28: first run
15
16
Machine: 8 cores, x86-64, NVMe (ext4 on LVM), release build, warm cache.
17
Files are 21 lines each in 100 directories; one change in ten appends a
18
line to `hot.txt`, the rest rewrite one ordinary file.
19
20
| Operation (10 000 files, 5 000 changes) | Time | Threshold | |
21
|---|---:|---:|---|
22
| commit: import 10 000 files | 1 031 ms | 60 000 ms | ok |
23
| commit: one file (mean of 4 999) | 3 761 ms | 250 ms | **over** |
24
| status: clean working copy (stat crawl) | 2 977 ms | 2 000 ms | **over** |
25
| status: 10 files modified | 3 062 ms | 2 000 ms | **over** |
26
| commit: 10 files | 9 089 ms | 500 ms | **over** |
27
| log: whole bookmark | 408 ms | 2 000 ms | ok |
28
| blame: hot file (500 lines) | 2 920 ms | 2 000 ms | **over** |
29
| blame: ordinary file | 2 927 ms | 1 000 ms | **over** |
30
| checkpoint | 596 ms | 10 000 ms | ok |
31
| status after checkpoint | 2 873 ms | 2 000 ms | **over** |
32
| push: everything to an empty remote | 782 ms | 60 000 ms | ok |
33
| push: up to date | 4 ms | 1 000 ms | ok |
34
| clone: everything, with checkout | 3 378 ms | 60 000 ms | ok |
35
| fsck | 7 955 ms | 60 000 ms | ok |
36
| gc | 9 489 ms | 60 000 ms | ok |
37
| status after gc | 2 829 ms | 2 000 ms | **over** |
38
39
Peak resident memory over the whole run: 1 405 MiB. The run took 5 h 14 min,
40
almost all of it building the history, because each commit costs as much
41
as a status.
42
43
Smaller runs, same machine:
44
45
| Files, changes | Mean commit | Clean status | Blame (hot) | Peak memory |
46
|---|---:|---:|---:|---:|
47
| 1 000, 200 | 90 ms | 62 ms | 62 ms | 70 MiB |
48
| 1 000, 800 | 166 ms | 130 ms | 119 ms | 118 MiB |
49
| 4 000, 200 | 343 ms | 235 ms | 239 ms | 254 MiB |
50
| 10 000, 5 000 | 3 761 ms | 2 977 ms | 2 920 ms | 1 405 MiB |
51
52
### What it shows
53
54
Sync, log, checkpoints and repository maintenance are fine. Everything
55
that snapshots the working copy (status, commit, blame of the working
56
copy's base) grows with both the number of files and the length of the
57
history. Timing the phases of one snapshot at 4 000 files and 300 changes:
58
59
| Phase | Time |
60
|---|---:|
61
| load the base state (checkpoint plus the changes since) | 75–130 ms |
62
| materialize every file of the base state | 75 ms |
63
| walk the working copy against the manifest | 50 ms |
64
| build the working-copy change | 8 ms |
65
66
A clean status should be a stat walk and nothing else. The fix is backlog
67
item O10: skip loading and materializing when every file's stat matches a
68
manifest written for the same base, make the base state lazy for the
69
callers that need it, and cache materialized snapshots per state. The
70
thresholds above stay as they are until then, so the harness reports the
71
gap rather than hiding it.