A tachometer for code.
Caution
tak is pre-v1. Its CLI, configuration, storage format, and behavior are not finalized.
Breaking changes may land between releases, including changes that require existing configuration or recorded data to be updated. If you need a stable benchmark tool, use hyperfine. If you need CI benchmark tracking, use Bencher or CodSpeed.
Wall-clock time on a shared CI runner has roughly the same noise floor as the regressions people want to catch. tak asks whether retired instruction counts can provide a deterministic signal instead.
Measured on a 32-core Linux host:
| metric | quiet host | under 32-way CPU contention | median drift |
|---|---|---|---|
| instructions (cachegrind) | 0.008–0.027% CV | 0.011–0.021% CV | ≤0.035% |
| wall clock | 3.9–20.6% CV | 14.2–19.2% CV | +147% to +164% |
That produces one narrow rule: gate on instruction counts; report wall time without gating on it. Syscall counts and peak RSS move with thread scheduling and are not deterministic enough for a tight threshold.
Measurements stay in the repository as JSON lines under refs/notes/tak, merged with git's
cat_sort_uniq strategy. There is no database, account, or hosted service.
Read the methodology for the measurements, limitations, and reasoning.
tak runmeasures wall time and, where Valgrind is available, instruction countsallocations = trueortak run --allocationsalso counts heap allocations under Valgrind's DHAT. They are recorded and shown intak compare, and never gatetak.tomldeclares repeatable benchmarks for local and CI runs- a benchmark can also record custom metrics, such as a file's size in bytes or a number a command prints. They are stored and reported beside the timings, and never gated
tak run --record,tak push, andtak historystore results in git notestak artifact exportandtak artifact publishhand measurements from a read-only CI job to a separately trusted publishertak comparereports changes and gates only on instruction counts. It fails when nothing was measured on both sides, unless theallow_emptysetting is on ([gate] allow_empty,TAK_ALLOW_EMPTYor--allow-empty), which passes that case with a warning, or--no-gateis given. Underallow_emptya regression still fails;--no-gatenever fails on the comparison, though errors such as an invalidtak.tomlstill dotak compare --accept BENCHaccepts an intentional regression in one named benchmark while every other benchmark still gates;Tak-Accept:commit trailers do the same once a project opts intak run --save-baseline NAMEandtak run --baseline NAMEcompare a local, uncommitted change against a saved measurement, without touching git notestak run --profile-dirandtak explainshow which functions an instruction-count change came fromtak detectreports instruction-count steps that already landed on a branch, and fails when the newest recorded commit introduced one or when nothing could be comparedtak logshows each benchmark's measurements over first-parent history, as Markdown or as a self-contained HTML reporttak backfillmeasures published release binaries, or builds and measures past commits with--commits, to bootstrap history
tak itself does not post to pull requests. jdx/tak-action,
which is also pre-v1, runs tak compare on a pull request and reports the result as a sticky
comment and a check run. See Adopt tak in a project.
Change-point detection does not exist. tak detect compares consecutive recorded points
against the gate; it is not statistical change-point detection.
The crate is tak-cli; the binary is tak. Releases are automated as described in
RELEASING.md.
Use mise so local and CI commands stay aligned:
mise run build
mise run test
mise run lint
mise run ciInstruction-count tests require Valgrind. Run tak doctor to see what is available on the
current host.
MIT