Skip to content

Per-mutant timeout budget is parallelism-blind — full-core runs convert contention into spurious timeout verdicts #545

Description

@JonasPammerWork

[boxed/mutmut] Per-mutant timeout budget is parallelism-blind — full-core runs convert contention into spurious ⏰ verdicts

Summary

The per-mutant wall/CPU budget ((estimated_time_of_tests + 1) * 15 / * 30) is computed from a solo-run estimate, but mutmut run defaults to forking one child per core, all hammering the same test database and CPUs. Under that contention each child's covering set runs several times slower than the estimate assumes, so the fixed deadline converts scheduler contention into timeout verdicts.

Measurements (6-core runner, DB-bound Django suite)

  • Default parallelism, cold cache: run "finishes" in ~20 min with 616 ⏰ at ~1 s per "timeout" — the verdicts are contention artifacts, not scores.
  • Same tree, mutmut run --max-children 2, cold cache: 708 🎉 / 24 🙁 / 366 ⏰ in ~83 min (~96.7 % of scored mutants killed) — the residual ⏰ being the fixed-budget issue reported separately (missing call.when filter starves the estimate).

So the same code and tests score wildly differently depending only on child count — and nothing warns about it.

Compounding trap: cached ⏰ verdicts replay as final

Resume-from-cache replays previously recorded ⏰ verdicts across config generations: after changing the covering set's cost (or --max-children), a "resumed" run still reports the old timeouts. A meaningful re-score requires a cold mutants/ — worth documenting, or invalidating cached ⏰ (only ⏰) on config change.

Suggested fixes (any of)

  1. Scale the deadline by the number of concurrent children (estimate × children is a cheap upper bound for a shared-resource suite).
  2. Re-measure the baseline estimate AT the configured parallelism before scoring.
  3. Expose the multiplier/constant as config (the ask in closed Allow configuring timeout multiplier and constant #492) so operators can compensate explicitly.
  4. At minimum: document that DB-bound suites need --max-children well below core count, and that ⏰ verdicts from a differently-parallel run must not be resumed.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions