From 7167812c71139d8a2ee60016d9834b49cea1ac9e Mon Sep 17 00:00:00 2001 From: PA Dev Bot <344001113+pa-devbot@users.noreply.github.com> Date: Tue, 3 Nov 2026 10:11:12 +0000 Subject: [PATCH] UnitTestRunner: run tests on the uncapped normal thread pool The runner dispatches each test via ThreadPool::dispatch_now_blocking(), which blocks the dispatcher thread when the pool is at capacity. It was dispatching into computation_normal(), which is capped at hardware_concurrency, while the runner itself allows up to 2*hardware_concurrency concurrent tests. The mismatch means the dispatcher can park in dispatch_now_blocking() waiting for a pool slot; combined with threads stuck mid-task (e.g. in a blocking log call), the whole run can stall. Use unlimited_normal() instead: the runner already caps the number of concurrently running tests, so the pool just needs to be able to honor that cap rather than impose a smaller one of its own. --- .../ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp b/SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp index e34d1cbba1..8448f23aad 100644 --- a/SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp +++ b/SerialPrograms/Source/ComputerPrograms/ComputerPrograms_UnitTestRunner.cpp @@ -254,10 +254,12 @@ void UnitTestRunner::program(ProgramEnvironment& env, CancellableScope& scope){ m_env = nullptr; }); + // Uncapped pool: the runner caps the # of concurrently running tests itself, and + // dispatch_now_blocking() would stall the dispatcher once a capped pool saturates. PokemonAutomation::UnitTestRunner runner( &scope, env.logger(), - GlobalThreadPools::computation_normal() + GlobalThreadPools::unlimited_normal() ); runner.add_listener(*this); @@ -372,9 +374,11 @@ bool CommandLineUnitTestRunner::run(bool augment_color_distortions){ m_logger.log("Color distortion augmentation enabled. Image tests with labeled images also run with: " + labels); } + // Uncapped pool: the runner caps the # of concurrently running tests itself, and + // dispatch_now_blocking() would stall the dispatcher once a capped pool saturates. PokemonAutomation::UnitTestRunner runner( m_logger, - GlobalThreadPools::computation_normal() + GlobalThreadPools::unlimited_normal() ); runner.add_listener(*this); for (const auto& test : UNIT_TESTS_ALL()){