How it stays light
- Never writes to repositories: git runs with optional locks and the diff
index refresh off, so it never takes
index.lockfrom under an agent. - One background worker per column watches the working tree with inotify and
refreshes once changes settle: after twice what its last refresh cost
(100 ms to 1 s), so an edit shows in about 0.1 s and refreshing never takes
more than a third of a core while an agent keeps writing. Paths git ignores
(
target/,node_modules/) never trigger a refresh. No timers: an idle repository costs nothing, even one with 485k files. Linked worktrees and submodules are watched through their git directories too, and a folder that is not a repository is not watched at all. A folder inside a repository that cannot be read (a container's data volume, say) is left out of the watch, not the whole repository; when watching fails anyway, the Repositories row shows a warning and says why. - The watcher already knows which paths changed, so an edit reads the status
of those paths alone and merges it into the last one (git's own fsmonitor
would need to write the index). History is read again only when HEAD or a
ref moves, and without
--topo-orderunless the repository has a commit-graph file (otherwise git walks the whole history first). - A model thread turns snapshots into row edits and wakes a column only when a flash ends or its "changed … ago" label turns over; the UI thread only applies the edits and draws.
- Line counts follow the status in a second snapshot, so an edit shows as
fast as before and its
+12 −3a moment later (counting walks the index again: about as long as the status of the edited paths). New files are counted directly, up to 2,000 of them and 4 MiB each. - Diffs are capped at 5,000 lines, 8 MiB and 2,000 characters per line.
Measured on a Firefox checkout (485k files, 1M commits) and seven columns:
| before | after | |
|---|---|---|
| Refresh after an edit (Firefox) | 8.2 s | 0.19 s |
| Refresh after an edit (small repo) | 12 ms | 2 ms |
| Edit to snapshot | 300 ms | 100 ms |
| Idle model tick, 10k changed files × 7 | 95 ms | 1 µs |
| UI thread, hovering rows | 31% | 4% |
| UI thread, scrolling continuously | 74% | 15% |
| Idle | 0% CPU, 0 frames/s | the same |
The 1.0.0 release build, with two columns at 1600×1000 on an Xvfb display
(toolbox threads, 5 s windows): the UI thread sits below 0.5% of a core at
idle, at 2.4% while the pointer sweeps the rows and at 3.4% while the graph
scrolls continuously.
cargo run --release -p scm-core --example bench -- REPO… times the git
phases; cargo test --release -p ecliptic bench_ -- --ignored --nocapture
times the model and the UI updates. The toolbox keeps
the measuring repeatable: toolbox bench saves a baseline and compares a
later run against it, toolbox threads prints the per-thread shares in the
table above, and toolbox profile builds with frame pointers, records with
perf and folds the stacks.