Autoharness: verify harnesses in parallel by default - #4705
Conversation
Autoharness typically generates hundreds of harnesses, for which the sequential default of the shared harness runner is a poor fit: in a top-100 crates.io evaluation, 12 crates hit a 30-minute wall-clock cap. Kani already supports parallel harness verification behind --jobs (which requires --output-format=terse); with -j 16, num-traits went from timing out at 1800s to completing all 1,983 generated harnesses in 330s. Default autoharness to --jobs (thread-pool default) with terse output when the user passes neither option. Explicit choices are always preserved: --output-format=regular restores sequential verification with detailed output, and the parse-time validation that --jobs requires terse output is unaffected. Plain 'kani'/'cargo kani' verification is unchanged. To distinguish an explicit --output-format=regular from the clap default, the output_format argument becomes Option<OutputFormat> with an accessor defaulting to Regular. Existing autoharness tests assert on ordered per-harness output, so they pin --output-format=regular (also covering the opt-out); a new test pins the parallel default via order-independent assertions. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
1f63f3d to
324c598
Compare
324c598 to
4d57934
Compare
|
Both addressed.
Docs example: also a real defect. The example now passes |
They assert on ordered per-harness regular output, like the autoharness tests pinned previously; missed because their directory names do not match the autoharness glob. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
4d57934 to
d342cec
Compare
Description
Autoharness typically generates hundreds of harnesses, for which the sequential default of the harness runner is a poor fit. In a top-100 crates.io evaluation (tracking issue #3832), 12 crates hit a 30-minute wall-clock cap; with
-j 16 --output-format=terse, num-traits alone went from timing out at 1800s to completing all 1,983 generated harnesses in 330s.Kani already has the machinery (
--jobs, whose rayon pool covers the full per-harness pipeline: goto-instrument, loop-contract synthesis, CBMC). This PR makes autoharness use it by default.To distinguish an explicit
--output-format=regularfrom the clap default,output_formatbecomesOption<OutputFormat>with an accessor defaulting toRegular.Defaulting rules (
apply_autoharness_parallel_defaults), applied for theautoharnesssubcommand only:--output-formatis defaulted totersewhen the user did not pass it.--jobsis defaulted to-j(the thread pool's default thread count) when the user did not pass it and the resulting format isterse.So:
autoharness-j+ terseautoharness --jobs=N-j N+ terseautoharness --output-format=terse-j+ terseautoharness --jobs=1autoharness --output-format=regular(orold)autoharness --jobs=N --output-format=regularkani/cargo kani--jobsstill requires--output-format=terseThe defaults are applied in
mainimmediately after parsing and before validation, so validation sees the options the run will actually use. Otherwise a bare--jobs=Nwould be rejected for lacking--output-format=terseeven though autoharness supplies exactly that default — i.e. the documented "pass-j <N>to control the number of threads" would not have worked. The call is idempotent and is repeated insetup_sessionso a session is configured correctly however it was constructed.Note on memory: each thread runs its own CBMC process, so peak memory grows with the thread count, and the default is one thread per logical CPU. The docs call this out and point at
--jobs=<N>as the knob.Results themselves stay deterministic:
harness_runnercollects with rayon's indexedcollect::<Result<Vec<_>>>(), which preserves input order, so the summary table,--sarif, and--export-jsonare unaffected by execution order. Only live stdout ordering varies, which is what theThread N:prefix and the terse requirement address.Testing
cargo_autoharness_paralleltest pins both halves of the default with order-independent assertions: terse output (absence of per-check detail, independent of the CPU count), thread prefixes (skipped in a single-CPU environment rather than failing spuriously), the sorted per-function summary lines, and the totals line.kani-driverunit tests:check_autoharness_parallel_defaultscovers every combination in the table above plus "plain verification unaffected";check_jobs_still_requires_tersepins that an explicit non-terse format with--jobsremains an error for bothautoharnessand plain verification.Status:/Description:/Check N:), which only--output-format=regularprints, now pass that flag — this also covers the opt-out path. That is 12 tests, includingcargo_autoharness_bounded,cargo_autoharness_slicesandcargo_autoharness_smart_pointers, which were added after this PR was opened.assume_invariant,fmt_impls,generics,list,raw_pointers,exclude_precedence) deliberately keep the new default, so CI exercises the parallel/terse path beyond the dedicated test. Their expected output only references the sorted summary/skipped tables and totals, and compiletest matches expected lines independently of order.script-based-presuite (66 tests),uisuite,cargo test -p kani-driver(81 tests),clippy --all-targets, andkani-fmt --checkpass.kani/cargo kanioutput is unchanged.Towards #3832 (evaluation throughput).
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.