Skip to content

Commit d69b22d

Browse files
giordanoclaude
andcommitted
Stop parallel workers when serial tests are at the end
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 13c2c5f commit d69b22d

2 files changed

Lines changed: 66 additions & 19 deletions

File tree

src/ParallelTestRunner.jl

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,8 +1082,31 @@ function runtests(mod::Module, args::ParsedArgs;
10821082
#
10831083

10841084
tests_to_start = Threads.Atomic{Int}(length(tests))
1085+
# After parallel-before-serial: stop extra workers so only one process is alive for
1086+
# serial tests, but keep one parallel worker so we do not add a third addworker (ID_COUNTER).
1087+
function drain_pool_leaving_one_worker!(pool, njobs)
1088+
alive = PTRWorker[]
1089+
for _ in 1:njobs
1090+
p = take!(pool)
1091+
if p !== nothing && Malt.isrunning(p)
1092+
push!(alive, p)
1093+
end
1094+
end
1095+
while length(alive) > 1
1096+
Malt.stop(pop!(alive))
1097+
end
1098+
kept = isempty(alive) ? nothing : alive[1]
1099+
if kept !== nothing
1100+
put!(pool, kept)
1101+
end
1102+
for _ in 1:(njobs - (kept === nothing ? 0 : 1))
1103+
put!(pool, nothing)
1104+
end
1105+
end
10851106
try
1086-
for (phase_tests, sem, shared_worker) in test_phases
1107+
phases = test_phases
1108+
for i in 1:length(phases)
1109+
phase_tests, sem, shared_worker = phases[i]
10871110
isempty(phase_tests) && continue
10881111
# for serial phases, reserve one pool slot for the shared worker
10891112
if !isnothing(shared_worker)
@@ -1197,6 +1220,14 @@ function runtests(mod::Module, args::ParsedArgs;
11971220
put!(worker_pool, shared_worker[])
11981221
shared_worker[] = nothing
11991222
end
1223+
# parallel workers are not stopped while serial tests remain (tests_to_start > 0);
1224+
# drain before serial-after so only one worker is alive for the serial phase
1225+
if isnothing(shared_worker) && i < length(phases)
1226+
next_tests, _, next_sw = phases[i+1]
1227+
if !isempty(next_tests) && !isnothing(next_sw)
1228+
drain_pool_leaving_one_worker!(worker_pool, jobs)
1229+
end
1230+
end
12001231
end
12011232
catch err
12021233
if !(err isa InterruptException)

test/runtests.jl

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -840,47 +840,63 @@ end
840840
end
841841

842842
@testset "serial tests run before parallel (default)" begin
843+
serial_test_body = quote
844+
children = _count_child_pids($(getpid()))
845+
# Make sure serial tests run alone.
846+
if children >= 0
847+
@test children == 1
848+
end
849+
end
843850
testsuite = Dict(
844-
"serial_a" => :(),
845-
"serial_b" => :(),
851+
"serial_1" => serial_test_body,
852+
"serial_2" => serial_test_body,
853+
"serial_3" => serial_test_body,
846854
"parallel_1" => :(),
847855
"parallel_2" => :(),
856+
"parallel_3" => :(),
848857
)
849858
io = IOBuffer()
850859
jobs = 2
851860
old_id_counter = ParallelTestRunner.ID_COUNTER[]
852-
runtests(ParallelTestRunner, ["--jobs=$(jobs)", "--verbose"];
853-
testsuite, stdout=io, stderr=io,
854-
serial=["serial_a", "serial_b"])
861+
@show_if_error io runtests(ParallelTestRunner, ["--jobs=$(jobs)", "--verbose"];
862+
testsuite, stdout=io, stderr=io,
863+
init_code=:(include($(joinpath(@__DIR__, "utils.jl")))),
864+
serial=["serial_1", "serial_2", "serial_3"])
855865
str = String(take!(io))
856-
@test contains(str, "2 serial test(s) will run before")
866+
@test contains(str, "Running 6 tests using 2 parallel jobs")
867+
@test contains(str, "3 serial test(s) will run before")
857868
@test contains(str, "SUCCESS")
858869
@test ParallelTestRunner.ID_COUNTER[] == old_id_counter + jobs
859870
end
860871

861872
@testset "serial tests run after parallel" begin
862-
testsuite = Dict(
863-
"serial_x" => quote
864-
children = _count_child_pids($(getpid()))
865-
# Make sure serial tests run alone.
866-
if children >= 0
867-
@test children == 1
873+
serial_test_body = quote
874+
children = _count_child_pids($(getpid()))
875+
# Make sure serial tests run alone.
876+
if children >= 0
877+
@test children == 1
868878
end
869-
end,
870-
"parallel_y" => :(),
879+
end
880+
testsuite = Dict(
881+
"serial_1" => serial_test_body,
882+
"serial_2" => serial_test_body,
883+
"serial_3" => serial_test_body,
884+
"parallel_1" => :(),
885+
"parallel_2" => :(),
886+
"parallel_3" => :(),
871887
)
872888
io = IOBuffer()
873889
ioc = IOContext(io, :color => true)
874890
old_id_counter = ParallelTestRunner.ID_COUNTER[]
875891
@show_if_error io runtests(ParallelTestRunner, ["--jobs=2", "--verbose"];
876892
testsuite, stdout=ioc, stderr=ioc,
877893
init_code=:(include($(joinpath(@__DIR__, "utils.jl")))),
878-
serial=["serial_x"], serial_position=:after)
894+
serial=["serial_1", "serial_2", "serial_3"], serial_position=:after)
879895
str = String(take!(io))
880-
@test contains(str, "Running 2 tests using 1 parallel jobs")
881-
@test contains(str, "1 serial test(s) will run after")
896+
@test contains(str, "Running 6 tests using 2 parallel jobs")
897+
@test contains(str, "3 serial test(s) will run after")
882898
@test contains(str, "SUCCESS")
883-
@test ParallelTestRunner.ID_COUNTER[] == old_id_counter + 1
899+
@test ParallelTestRunner.ID_COUNTER[] == old_id_counter + 2
884900
end
885901

886902
@testset "serial_position validation" begin

0 commit comments

Comments
 (0)