OXYGENHUB

Benchmarks: S1's first round on the Linux tree (refs #41) bd9414401fdc

Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-30 21:55 UTC
Signature
✔ signed by Andy McCall
Hash
bd9414401fdcf3c5bb8073bf523139d1d6270ac1389519fc8ac7485882ad005c
Depends on
1d360c91a289 61e9ad6ddc2d e4b8bcf04a86
Depended on by
e82591ec33a4
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
2 atoms, 0 tree operations, 2 files

Browse the tree at this change

modified docs/backlog-overnight-4.md +2 −0
…
115 unchanged lines
116 116
  changed-only builds and the manifest cache already in).
117 117
118 118
- 2026-09-30 **B0** baseline (table in `docs/benchmarks.md`; `linux-bench.sh` now runs three of each, alternating, plus a local clone; the loop-3 script is kept as `linux-bench.sh.loop3`). oxy is ahead on the first commit (33.3 s against 38.2 s) and gc (48 s against 100 s); clean status is close (0.43 to 0.53 s against 0.34 to 0.46 s). Behind: dirty status and diff (1.5 to 2.2 s against 0.3 to 0.8 s), commit (2.5 to 3.1 s against 0.4 to 0.5 s), log (0.9 s against 0.00 s), blame (1.0 s against 0.07 s), checkout (3 s against 0.4 to 0.5 s), fsck (24 s against 13 s), and a new gap: a local clone takes 56 s and 3.3 GB against Git's 18 s. The store after gc is 375 MB (it now includes the 48 MB state index) against 295 MB.
119 +
120 +
- 2026-09-30 **S1, first round** (commits c9dca9ed to 077e899b; table in `docs/benchmarks.md`). A lister of our own replaces the ignore crate's walker (listing 0.5 s to 0.18 s); the manifest is a flat binary file with hashes and graph keys as bytes; the state index keeps each file's history encoded until used (a writer bug I made on the way was caught only on Earth, since a failed index read falls back to a full load: test builds now read every index written back); maps are built in path order; mimalloc is the allocator. Clean status is now ahead of Git (0.18 s against 0.22 s), the first commit too (24.4 s against 36.2 s), and gc (29.9 s against 70.3 s). One-file status is 0.47 s against 0.22 s. Log (S3, first part): metadata from the state index and a store cache, signature marks without reading changes: 0.20 s, of which 9 ms is the log. For Andy: `oxy log` checks the working copy first (about 0.18 s here); Git's log does not look at it. Dropping that check would make log about 20 ms, but the working-copy line would then show the last snapshot's state.
modified docs/benchmarks.md +41 −0
…
626 unchanged lines
627 627
(48 s against 100 s). The store after gc grew from 324 MB because it now
628 628
includes the workspace's state index.
629 629
630 +
631 +
### S1, first part: walk, manifest, lazy index, mimalloc (2026-09-30 22:39, oxygen#41)
632 +
633 +
The same script after the first round of S1: a lister of our own in place
634 +
of the ignore crate's walker, the manifest as a flat binary file with
635 +
hashes as bytes, each file's history in the state index decoded only when
636 +
used, maps built in path order, and mimalloc as the allocator. Earth's
637 +
load average was 4 to 5 (no Flow jobs); runs alternate with Git.
638 +
639 +
| Operation | oxy | before (21:43) | Git |
640 +
|---|---:|---:|---:|
641 +
| init and commit the tip | **24.4 s**, 3.2 GB | 33.3 s, 3.1 GB | 36.2 s |
642 +
| status, clean | **0.17 to 0.18 s**, 130 to 150 MB | 0.43 to 0.53 s | 0.22 to 0.23 s |
643 +
| status, one file | 0.47 s (1.47 s first) | 1.73 to 1.81 s | 0.22 to 0.23 s |
644 +
| diff, one file | 0.47 to 0.51 s | 1.77 to 2.24 s | 0.11 to 0.14 s |
645 +
| commit, one file | 0.96 s | 3.10 s | 0.17 s |
646 +
| status, 1 000 files | 0.65 s (1.99 s first) | 1.62 s | 0.23 to 0.24 s |
647 +
| diff, 1 000 files | 0.65 s | 1.54 to 2.40 s | 0.46 to 0.48 s |
648 +
| commit, 1 000 files | 1.20 s | 2.47 s | 0.50 s |
649 +
| log -n 100 | 0.48 to 0.53 s | 0.86 to 1.03 s | 0.00 s |
650 +
| blame MAINTAINERS | 0.59 s | 0.99 to 1.04 s | 0.07 s |
651 +
| clone, local path | 36.7 s, 3.6 GB | 56.3 s | 18.0 s |
652 +
| checkout the first state, and back | 1.48 s, 1.37 s | 2.86 s, 3.00 s | 0.35 s, 0.34 s |
653 +
| fsck | 14.0 s, 1.0 GB | 24.4 s | 12.6 s |
654 +
| gc | **29.9 s** | 48.1 s | 70.3 s |
655 +
| store after gc | 369 MB | 375 MB | 295 MB |
656 +
657 +
mimalloc alone took one-file status from 0.78 to 0.47 s and clean status
658 +
from 0.26 to 0.18 s: status allocates hundreds of thousands of small
659 +
values from every thread, and glibc's arena locks were the largest single
660 +
cost. The first status after a commit (1.47 s) rebuilds the state index.
661 +
662 +
Afterwards (22:55), log reads change metadata from the state index and a
663 +
metadata cache in the store, and its signature marks no longer read each
664 +
change whole: `log -n 100` takes 0.19 to 0.20 s, of which 9 ms is the log
665 +
itself and the rest the check that the working copy is clean.
666 +
667 +
Where one-file status goes now (0.47 s): listing the working copy about
668 +
150 ms (the syscalls alone: `find` with a stat of each file takes 0.37 s
669 +
on one core), loading the state index about 60 ms, reading the manifest
670 +
about 40 ms, rendering and diffing the changed file about 100 ms.