OXYGENHUB

Backlog 4: beating Git on the Linux tree 61e9ad6ddc2d

refs #41
Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-30 20:42 UTC
Signature
✔ signed by Andy McCall
Hash
61e9ad6ddc2d8a7b7ad698809e7ea5167a08b8b1ee1a62a9a999932de2be4fae
Depends on
ff0af1ee299d
Depended on by
3d7120efe04a bbe654f95806 bdddd0c53720 3110dc5bea4c edc16b3ab30f 0c15e4678479 7cdc070ca541 6e2b12dfe6ec 332c1241a11c cb9a097def6f 7f75b41c107d 72215f29df4c e82591ec33a4 e266b7d4065c bd9414401fdc e4b8bcf04a86 abdbc768c6e8 c69733a3ce59
In bookmarks
agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
In tags
v0.10.0 v0.11.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
Edits
1 atom, 1 tree operation, 1 file

Browse the tree at this change

added docs/backlog-overnight-4.md +116 −0
1 +
# Overnight backlog 4: beating Git on the Linux tree
2 +
3 +
Loop 3 made oxy usable on the Linux kernel. This loop aims to make it
4 +
faster than Git wherever the model allows it, with the kernel tree as the
5 +
yardstick. Correctness is never traded for speed: every item keeps its
6 +
tests, and the test builds that compare an incremental structure with a
7 +
full computation stay on.
8 +
9 +
## The yardstick
10 +
11 +
The Linux tip on Earth (`~claude/bench/linux`, 95 943 files, 1.8 GB):
12 +
`o` is the oxy repository and `g` the Git one. Git is 2.53.
13 +
14 +
| Operation | oxy (2026-09-30) | Git | Target |
15 +
|---|---:|---:|---|
16 +
| init and first commit | 38.5 s, 4.4 GB peak RSS | 38.8 s | under Git, under 2 GB |
17 +
| status, clean | 0.41 to 0.43 s | 0.26 to 0.32 s | at or under Git |
18 +
| status, one file edited | 1.26 to 1.39 s | 0.26 to 0.29 s | at or under Git |
19 +
| diff, one file | 1.19 to 1.45 s | 0.16 to 0.25 s | at or under Git |
20 +
| commit, one file | about 3.1 s | 0.45 s | under 0.5 s |
21 +
| status, diff and commit, 1 000 files | 3.9, 2.8 and 4.9 s | 0.41, 0.95 and 0.57 s | at or under Git |
22 +
| log -n 100 | 1.39 s | 0.01 s | under 0.05 s |
23 +
| blame MAINTAINERS | 1.18 s | 0.09 s | at or under Git |
24 +
| checkout to the first state and back | 2.2 to 2.8 s | 0.42 to 0.47 s | at or under Git |
25 +
| fsck | 22.1 s | 13.1 s | at or under Git |
26 +
| gc | 39.7 s | 102.8 s | stays ahead |
27 +
| store after gc | 324 MB | 295 MB | at or under Git |
28 +
29 +
Where one-file status time goes now (Earth, loaded):
30 +
- index load: 0.16 to 0.28 s
31 +
- walk: 0.45 to 0.7 s
32 +
- manifest check before the snapshot: 0.1 s
33 +
- placeholders for unchanged files: 0.09 s
34 +
- tracked paths: 0.04 s
35 +
36 +
## Rules for this loop
37 +
38 +
- **Measure quietly.** Earth runs OxygenFlow jobs, for every push to the
39 +
  Oxygen repositories and for metalgear. Measure when `pgrep firecracker`
40 +
  finds nothing if you can; otherwise run oxy and Git alternately, three
41 +
  times each, and record the load average. Push your commits after a
42 +
  measurement, not before, since each push starts jobs.
43 +
- **Build the bench binary** from the synced source:
44 +
  `rsync -a --delete --exclude target --exclude .oxy ~/development/oxygen/ claude@earth:bench/oxygen/`,
45 +
  then `CARGO_TARGET_DIR=~/bench/idxbin cargo build --release` there. Use
46 +
  `~/bench/prof-status.sh`, `~/bench/vs-git.sh` and `~/bench/linux-bench.sh`,
47 +
  and extend them rather than writing one-off commands.
48 +
- **Phase timings** (`OXY_TIMINGS=1`) name where time goes. Add phases where
49 +
  they are missing before optimising.
50 +
- **An index is derived.** Every new index or cache is keyed by what it
51 +
  describes, can be rebuilt from the changes at any time, and has a test
52 +
  build check that compares it with a full computation (as the state index,
53 +
  tree view and kept file order do).
54 +
- **Formats change freely before 1.0,** but a change format bump follows the
55 +
  order in loop 3's backlog (old binary commits it; then the runner and hub
56 +
  pins; then `make install`).
57 +
58 +
## Speed
59 +
60 +
- [ ] B0 **Baseline.** Update `~/bench/linux-bench.sh` for today's build (the
61 +
  state index, the manifest cache, clean and dirty status, diff, commit,
62 +
  log, blame, checkout, a local clone, fsck, gc, store size) with three runs
63 +
  each and oxy and Git alternating. Record the table in `docs/benchmarks.md`.
64 +
- [ ] S1 **Status and diff at Git's speed** (oxygen#41). In order, measuring
65 +
  after each:
66 +
  - the manifest as a compact binary file read without a parse per line;
67 +
  - the walk: compare each file's stat with the manifest without building
68 +
    a path string per entry (sorted walk against a sorted manifest), and
69 +
    skip the `.oxyignore` machinery inside tracked directories where it
70 +
    cannot change the answer;
71 +
  - no placeholder `FileState` for unchanged files (audit every user of
72 +
    `SnapshotResult.base_snapshot.files` first);
73 +
  - load the state index lazily: memory-map it and decode a file's deferred
74 +
    history only when that file is built;
75 +
  - one pass for status: the manifest check and the snapshot walk share
76 +
    their stats.
77 +
- [ ] S2 **Commit at Git's speed.** A commit extends the base it already
78 +
  loaded: write the new state index from the old one plus the change, rather
79 +
  than loading history again, and do not render what the snapshot rendered.
80 +
  Target: one file under 0.5 s, 1 000 files under 0.6 s.
81 +
- [ ] S3 **The change index: log in milliseconds.** Per state, the changes in
82 +
  topological order with their generation numbers and where each change's
83 +
  metadata is, built from the parent state's index plus the new change.
84 +
  `oxy log -n 100` reads 100 entries. Target: under 0.05 s.
85 +
- [ ] S4 **The node index: blame and file history.** Per node, the changes
86 +
  that touch it, so blame and `oxy log FILE` cost that file's history.
87 +
  Target: blame MAINTAINERS at or under Git.
88 +
- [ ] S5 **Checkout by comparing indexes.** Compare the two states' tree
89 +
  indexes by rendered content hash and write only the files that differ.
90 +
  Target: at or under Git.
91 +
- [ ] S6 **fsck at or under Git**: parallel object checking and a cheaper
92 +
  state pass.
93 +
- [ ] S7 **The first commit ahead of Git, under 2 GB**: stream reading,
94 +
  hashing and storing a batch of files at a time, so the whole tree's text
95 +
  is never in memory at once.
96 +
97 +
## Space
98 +
99 +
- [ ] P1 **Store at or under Git after gc** (324 MB against 295 MB): measure
100 +
  what takes the space, then try a trained zstd dictionary per repository
101 +
  and packing similar objects together.
102 +
103 +
## Also
104 +
105 +
- [ ] R1 **Rebase into the working copy** (oxygen#42, Andy's choice for the
106 +
  overnight loop): when `oxy rebase CHANGE --onto TARGET` would be
107 +
  conflicted, offer to leave the conflict in the working copy to resolve and
108 +
  commit, as `merge` does, rather than refusing.
109 +
- [ ] Z1 **Closing summary.** Re-run the full benchmark and summarise, for
110 +
  Andy, where oxy matches or beats Git on the Linux tree, and where it does
111 +
  not and why.
112 +
113 +
## Log
114 +
115 +
- 2026-09-30 Backlog written from the day's measurements (state index,
116 +
  changed-only builds and the manifest cache already in).