Tuning tman for cargo test

Rust

The longest quiet stretch of any common command; linking is the memory spike.

capstart atwhat it answers
stall30mhang backstop — no output and no CPU/IO activity for this long
max-time45mwall-clock budget — the only cap that bounds a run that is working but will never finish
max-memunset — opt in only if it has hurt youRSS ceiling across the process tree
max-parallel1slots per name-and-directory bucket

These are starting points derived from how cargo test behaves, not measurements of your machine. Every one of them should be replaced by a number you took from your own runs — the last section on this page is how.

.tman.kdl
alias "test" {
    command "cargo"
    args "test" "--all-features"
    max-time "45m"
    max-parallel 1
}

A cold cargo test on a dependency-heavy crate is the longest legitimately quiet stretch you are likely to hand tman. Without --verbose, cargo prints a compile line per crate and then nothing while rustc works, and a single large crate can take many minutes on its own.

Leave stall at the 30m built-in here, or raise it. This is the command the default was chosen for. If you want the run bounded, that is max-time — the two answer different questions, and only max-time answers "has this taken too long?".

The spike is at the end: linking a large binary with debug info, and LTO if it is enabled, can briefly want several gigabytes in a single process. That is why this guide recommends no max-mem by default — a ceiling sized for the compile phase will cull a perfectly healthy link. If you do set one, set it above your observed link peak and treat a 126 as a question about the link, not as a number to raise.

`max-parallel 1` on a shared target directory

Two cargo invocations against the same target/ serialise on its lock anyway, so a second slot buys nothing and costs you two processes holding memory instead of one. Since buckets are scoped per name and directory, a different crate in a different checkout is unaffected.

cargo nextest changes the picture on the test side — it streams per-test results, so the run phase is never quiet — but the build phase in front of it is unchanged, and that is the phase the stall backstop has to clear.

Turn the starting point into a real number

Everything above is derived from how this tool behaves, not from your machine. The numbers that matter come from your own runs, and getting them takes one command:

shell
tman status --json | jq '.runs[] | {name, exit, duration_ms}'

Set max-time from the slowest successful run you are willing to wait for, with real headroom — a cap that fires on healthy work teaches everyone to raise the cap, and after a few rounds of that it bounds nothing. Set stall from the longest stretch the command legitimately produces no output and no CPU, then double it.

Exit 124, 125, and 126 are findings, not flakes. 124 is a wall-clock timeout, 125 a stall, 126 a resource cull. Widening the cap that fired is the right response only after you know why it fired — the first two times a suite trips max-mem, the interesting question is what is holding the memory.

Frequently asked

What stall value should I use for cargo test?

The 30m built-in, or higher. A cold Rust build is the longest silence tman commonly sees, and stall is a hang backstop rather than a runtime budget — if you want the run bounded, use max-time, which is the cap that answers that question.

Should I set max-mem for cargo test?

Not by default. The peak is at link time, not compile time, and a ceiling sized for compilation will cull a healthy link of a large binary with debug info or LTO. If you set one, put it above your observed link peak.

Sources