Skip to content

* Run test fixtures in parallel - #813

Open
Hawkynt wants to merge 3 commits into
mainfrom
perf/parallel-tests
Open

Hawkynt wants to merge 3 commits into
mainfrom
perf/parallel-tests

Conversation

@Hawkynt

@Hawkynt Hawkynt commented Nov 10, 2026

Copy link
Copy Markdown
Owner

Test fixtures now run in parallel; tests within a fixture keep their order.

Why

The ubuntu-latest CI job reached 74–90 minutes and PR #811's run was cancelled at the 90-minute timeout with every step green. All ~42,900 tests ran sequentially.

Changes

  • [assembly: Parallelizable(ParallelScope.Fixtures)] (Compression.Tests/TestParallelism.cs).
  • Independence fixes: the two fixtures that change the process-wide InMemoryProcessing.ThresholdBytes are [NonParallelizable] (with the reason); the shared download/build caches serialise their fills and write downloads atomically.
  • Audit of the rest: Guid-named temp dirs, device-mapper names and mount points stay per fixture; NetBSD guests boot the shared image with snapshot=on.
  • The Performance step runs with NUnit.NumberOfTestWorkers=1 so timings are not skewed. CONTRIBUTING documents the independence rules.

Verification

Required tier, three parallel runs locally (16 cores): 7 m, 5 m 17 s, 5 m 11 s instead of 18 min, identical results each time (41,011 passed; the same 3 local-toolchain tests fail as in a sequential run).

Closes #812

Preparation for running fixtures in parallel; each change removes state two
fixtures could share.

- InMemoryProcessingTests and ConvertArchiveInMemoryTests set the
  process-wide InMemoryProcessing.ThresholdBytes (every conversion reads it),
  and the latter also counts every cwb_x2m_/cwb_fsconv_ temp directory:
  marked [NonParallelizable] with that reason.
- RetroImageCache, FreeDosCache, DmsdosCache: fixtures share one download/
  build cache directory; filling it is now serialised per cache (the others
  then hit the cache), and downloads land in a unique .partial file that is
  renamed into place, so no reader ever sees a half-written file.

Audited and left alone because they are already per-fixture: Guid-named temp
directories, device-mapper names and mount points; the NetBSD guest boots its
shared live image with snapshot=on and gets its own data disk per run.
Symptom (#812): the ubuntu-latest CI job took 74-90 minutes and PR #811's run
was cancelled at its 90-minute timeout with every step green; the core tier
alone took 18 min locally and 18-29 min on CI.

Root cause: all ~42,900 tests ran strictly one after another (no NUnit
parallelism), so wall-clock time was the sum of every test.

Fix: [assembly: Parallelizable(ParallelScope.Fixtures)] - fixtures run in
parallel, tests inside one fixture keep their order (fixture fields need no
locking). The performance step stays sequential (NumberOfTestWorkers=1) so
throughput measurements do not skew each other. CONTRIBUTING states the
independence rules.

Verified: the required tier ran three times in parallel on 16 cores - 7 m,
5 m 17 s, 5 m 11 s instead of 18 min - with identical results each time:
41,011 passed, and only the 3 tests that also fail sequentially on this host
(local lrelease version, no wsl binary, PyInstaller toolchain).

Closes #812
Symptom: on PR #813's CI run the bcachefs oracle failed with "Operations
that change non-concurrent collections must have exclusive access" in
FsInteropToolbox.WslHasTool - two fixtures probing tools at the same time
corrupted the cache.

Root cause: tool-availability caches shared by many fixtures were plain
Dictionary instances (FsInteropToolbox and the Erofs, Fat and FatPlus
conformance helpers), and Reiser4KernelOracle's one-time preparation - which
may download a kernel - could run twice at once.

Fix: the four tool caches are ConcurrentDictionary; Reiser4KernelOracle's
preparation is a Lazy<bool> that runs once. Swept the rest: the other static
probes are private to one fixture (whose tests run in order) or compute an
idempotent bool; the headless-UI recorders are used only by fixtures already
marked [NonParallelizable].

Verified: required tier in parallel again - 41,011 passed, same 3 local
toolchain failures, 5 m 11 s.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CI: the Linux test job runs into its 90-minute limit

1 participant