Take the log's order from git: torvalds/linux opens in 999 ms instead of 15.7 s - #484
Merged
Merged
Conversation
Opening torvalds/linux still costs 15.7s on current main, and the whole of it is one libgit2 call: a sorted revwalk materialises the complete ordered list before it yields a single oid, and libgit2 never reads the commit-graph that makes git's answer 188ms. Why: #479 fixed the per-page repayment (page ten went 157.67s -> 112ms) but deliberately left the first walk, which is now the entire large-repo problem. Measured fresh on a quiet machine, against 4c6b5ed. Also records a correction both #473 and #476 need: they propose shelling out to --topo-order, and that is the wrong ordering. libgit2's TIME|TOPOLOGICAL is byte-for-byte --date-order; --topo-order shares only 1,627 of the first 2,000 kernel oids, so adopting it would silently change which commits the first page shows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
refreshAll awaited eleven reads behind one Promise.all and wrote once, so status, branches, tags and HEAD — a second's work on torvalds/linux — waited fourteen more seconds for the log page. The log now lands in its own write. Why: the other ten reads are collectively fast on every fixture the benchmark covers, so joining them to the slowest read is what turns a one-second screen into a 15.7-second one. The page is still STARTED beside the others, so the eleven-way concurrency open_screen measures is unchanged, and refreshAll still resolves only once history has landed — callers refresh and then read commits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
torvalds/linux first screen 15.74s -> 999ms, first page 18.11s -> 222ms, deep 253ms -> 59ms. wide and refs are unmoved, which is right: their cost is status and ref enumeration, neither of which this touched. The fixtures now carry a --split commit-graph, written by bench-fixtures.mjs, because the app writes one on open and a fixture without one measures a state the app does not leave a repository in. The git baselines get the same file, so several ratios look worse than when we withheld it -- that is the correct comparison. The generated headline no longer asserts a cause it cannot see: it names the slowest remaining operation from the data, which is now file_history at 16.9s rather than the log. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #483. Opening
torvalds/linuxgoes from 15.74 s to 999 ms.Spec:
docs/superpowers/specs/2026-09-18-fast-log-walk-design.mdPlan:
docs/superpowers/plans/2026-09-18-fast-log-walk.mdMeasured
pnpm bench --linux, Apple M4 Pro, idle machine, before and after on the sameday and the same fixture:
status, untouched)Both acceptance criteria met: the kernel's first screen is under 1.5 s and is
now bounded by
status(1.03 s) rather than by history (8.7 ms), and the firstpage is under 500 ms.
What changed
Stage 1 — paint before history.
refreshAllawaited eleven reads behind onePromise.alland wrote once, so status, branches, tags and HEAD waited fourteenextra seconds for the log. The page is still started beside the others (the
eleven-way concurrency
open_screenmeasures is unchanged) but lands in its ownwrite, and
refreshAllstill resolves only once history has arrived.Stage 2 — the order comes from git.
build_walk_ordernow callsgit rev-list --date-order(git/log_walk.rs). Only oids cross over — commitmetadata still comes from libgit2 — so
log_cache,FrontierBuilder, cursorsand ref decorations are untouched. Any failure (git missing, non-zero exit,
unparseable output) falls back to today's libgit2 revwalk: a slow page, never a
failed one.
git/commit_graph.rskeeps a--splitcommit-graph warm, writtenin the background after open, honouring
core.commitGraph.The correction worth reviewing carefully
#473 and #476 both propose
--topo-order. It is the wrong ordering.Measured byte-for-byte on the kernel's first 2,000 oids:
--date-order--topo-orderTIME | TOPOLOGICAL(whatlog_pageuses)--topo-orderdoes not reorder the same commits — it returns different ones, soit would have silently changed which commits the first page shows.
tests/log_walk_ordering.rspins it, with a fixture whose branches interleave onpurpose; the violation was planted and confirmed red, then reverted. The
benchmark's baselines are corrected too.
Two things found on the way
Oid::from_straccepts abbreviated hex and zero-pads it, soabc123parses into a valid-looking oid naming nothing. Truncated
rev-listoutputwould have become a plausible order with one wrong entry instead of an obvious
failure. The parser requires full-length hex; a test records why.
bench-fixtures.mjs,because the app writes one on open and a fixture without one measures a state
the app does not leave a repository in. The
gitbaselines get the samefile, which makes several ratios look worse than when we withheld it. That is
the correct comparison.
Deliberately not here
localStorage; thewrite is a backend decision, so a toggle needs a new Tauri command to write git
config — a new user-facing surface in a change that already touches the hottest
read in the app. The opt-out that matters exists and is tested:
core.commitGraph. The spec records this.file_history— 16.9 s on the kernel and now the slowest operation there.Same root cause, its own cap, cancellation and cursor semantics (file_history walks all of history on a file with fewer than 500 commits, holding the exclusive lock #474, Cap the file-history walk, share the lock, and let it be cancelled #478).
log_filtered_pagekeeps a libgit2 walk on its cache-miss path for the samereason. Both earn their own issue.
Verification
cargo test— 1399 passed, 0 failed (102 binaries)pnpm test— 4184 passed (408 files)pnpm tsc --noEmit— cleanpnpm bench --linuxon an idle machine; all three published artifactsregenerated together and
test/benchmark.test.tsre-renders themsmoke,history-diff,open-persisted-screen,history-ops,commit,status-stage,file-history,repo-tabs🤖 Generated with Claude Code