Skip to content

Speed budgets

Speed is something furca promises, not something it hopes for. Each promise below is a budget: an operation, the kind of repository it is measured on, and how long it may take. The benchmark that measures them is part of the gate - a broken budget fails the build the same way a failing test does - and every release carries the numbers its own build measured on Windows, Linux and macOS.

Promised

Measured on a synthetic repository of 100,000 commits - a mainline with merged feature branches, open branches, tags and commits from slow clocks.

WhatRepositoryBudget
Open a repository and read the first 500 commits of its graph, from every branch and tagpacked+commit-graph< 100 ms
The same, on a repository without a commit-graph filepackedmeasured, not promised
Start the desktop app to its first drawn framepacked+commit-graph< 300 ms, measured from v0.7.0
Working tree status after a file is saved, in a repository of up to 10 000 filespacked+commit-graph< 50 ms, measured from v0.10.0
Show a 5 000-line diffpacked+commit-graph< 30 ms, measured from v0.9.0

packed: Not promised. Without generation numbers the exact order needs the whole history walked first, and git itself takes as long. The desktop app closes this by having git write the commit-graph.

Measured

ReleasePlatformRepositoryMedian90th percentileBudget
v0.3.0macos aarch64packed+commit-graph4.5 ms5.1 mskept (< 100 ms)
v0.3.0macos aarch64packed381.6 ms406.7 ms-
v0.3.0windows x86_64packed+commit-graph15.3 ms15.6 mskept (< 100 ms)
v0.3.0windows x86_64packed566.4 ms582.1 ms-
v0.3.0linux x86_64packed+commit-graph6.2 ms6.6 mskept (< 100 ms)
v0.3.0linux x86_64packed471.7 ms478.6 ms-
v0.2.0macos aarch64packed+commit-graph5.3 ms6.1 mskept (< 100 ms)
v0.2.0macos aarch64packed493.3 ms541.5 ms-
v0.2.0windows x86_64packed+commit-graph14.2 ms14.7 mskept (< 100 ms)
v0.2.0windows x86_64packed585.8 ms595.4 ms-
v0.2.0linux x86_64packed+commit-graph6.4 ms6.4 mskept (< 100 ms)
v0.2.0linux x86_64packed518.8 ms523.5 ms-

The repository is generated, not cloned: the same history on every machine and every run, built by git fast-import and then left the way git gc leaves a repository - one pack, packed refs, and a commit-graph file.

Each budget is timed 21 times after 3 warm-up runs, and the median is what the budget is held to; the 90th percentile is published next to it. A run starts from nothing: the repository is opened afresh each time, so the number is what a window pays when it opens a repository, not what a warm cache pays.

A median over the budget is measured once more after a pause before the build fails. A machine that is busy elsewhere slows every run for seconds at a time; a regression stays over the budget on the second try.

The graph is listed so that no commit comes before any of its children. Knowing that a commit has no children left to list means having looked at every commit that could be one. Generation numbers - stored in the commit-graph file that git gc writes - bound that search, so the first 500 commits of a long history touch a few thousand commits rather than all of them. Without the file, the exact order needs the whole history walked first; git log --date-order pays the same. See ADR 0005.

One measurement by hand, on one machine, on the repository above. The three tools do different amounts of work - Fork draws a window - so this is where the time goes for someone opening a repository, not a like-for-like benchmark.

Measured 2026-09-23 on Windows 11 laptop, 16 GB, with the usual work running alongside, on the budget fixture: 100 000 commits, packed, with a commit-graph.

ToolWhat was timedMedianRuns
furca 0.2.0furca log --all -n 500 --json, from starting the process to its last byte of output371 ms879 ms, 368 ms, 376 ms, 371 ms, 313 ms
git 2.42.0git log --all --date-order -n 500, from starting the process to its last byte of output436 ms523 ms, 436 ms, 360 ms
Fork 2.22.0Fork already running; the repository opened from the command line, until the head commit's details show3,075 ms3,579 ms, 2,681 ms, 3,075 ms