Skip to content

Commit

Permalink
Support for interactive threadpool in worker_nthreads (#69)
Browse files Browse the repository at this point in the history
* Support for interactive threadpool in `worker_nthreads`
* v1.4.3
  • Loading branch information
Drvi authored May 25, 2023
1 parent d24c783 commit f00d702
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "ReTestItems"
uuid = "817f1d60-ba6b-4fd5-9520-3cf149f6a823"
version = "1.4.2"
version = "1.4.3"

[deps]
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
Expand Down
31 changes: 27 additions & 4 deletions src/ReTestItems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,27 @@ struct TimeoutException <: Exception
msg::String
end

_is_good_nthread_str(str) = occursin(r"^(auto|[1-9]\d{0,4})$", str)
_validated_nworker_threads(n::Int) = n > 0 ? string(n) : throw(ArgumentError("Invalid value for `nworker_threads` : $n"))
function _validated_nworker_threads(str)
isok = true
if isdefined(Threads, :nthreadpools)
if ',' in str
t1, t2 = split(str, ',', limit=2, keepempty=true)
isok &= _is_good_nthread_str(t1) && _is_good_nthread_str(t2)
if isok
str = string(t1 == "auto" ? string(Sys.CPU_THREADS) : t1, ',', t2 == "auto" ? 1 : t2)
end
else
isok &= _is_good_nthread_str(str)
end
else
isok &= _is_good_nthread_str(str)
end
isok || throw(ArgumentError("Invalid value for `nworker_threads` : $str"))
return replace(str, "auto" => string(Sys.CPU_THREADS))
end

"""
ReTestItems.runtests()
ReTestItems.runtests(mod::Module)
Expand Down Expand Up @@ -100,8 +121,9 @@ will be run.
contain information for all runs of a `@testitem` that was retried.
- `nworkers::Int`: The number of workers to use for running `@testitem`s. Default 0. Can also be set
using the `RETESTITEMS_NWORKERS` environment variable.
- `nworker_threads::Int`: The number of threads to use for each worker. Defaults to 2.
Can also be set using the `RETESTITEMS_NWORKER_THREADS` environment variable.
- `nworker_threads::Union{String,Int}`: The number of threads to use for each worker. Defaults to 2.
Can also be set using the `RETESTITEMS_NWORKER_THREADS` environment variable. Interactive threads are
supported through a string (e.g. "auto,2").
- `worker_init_expr::Expr`: an expression that will be evaluated on each worker before any tests are run.
Can be used to load packages or set up the environment. Must be a `:block` expression.
- `report::Bool=false`: If `true`, write a JUnit-format XML file summarising the test results.
Expand Down Expand Up @@ -150,7 +172,7 @@ function runtests(
shouldrun,
paths::AbstractString...;
nworkers::Int=parse(Int, get(ENV, "RETESTITEMS_NWORKERS", "0")),
nworker_threads::Int=parse(Int, get(ENV, "RETESTITEMS_NWORKER_THREADS", "2")),
nworker_threads::Union{Int,String}=get(ENV, "RETESTITEMS_NWORKER_THREADS", "2"),
worker_init_expr::Expr=Expr(:block),
testitem_timeout::Real=DEFAULT_TEST_ITEM_TIMEOUT,
retries::Int=parse(Int, get(ENV, "RETESTITEMS_RETRIES", string(DEFAULT_RETRIES))),
Expand All @@ -161,6 +183,7 @@ function runtests(
logs::Symbol=default_log_display_mode(report, nworkers),
verbose_results::Bool=logs!=:issues && isinteractive(),
)
nworker_threads = _validated_nworker_threads(nworker_threads)
paths′ = filter(paths) do p
if !ispath(p)
@warn "No such path $(repr(p))"
Expand Down Expand Up @@ -201,7 +224,7 @@ end
# By tracking and reusing test environments, we can avoid this issue.
const TEST_ENVS = Dict{String, String}()

function _runtests(shouldrun, paths, nworkers::Int, nworker_threads::Int, worker_init_expr::Expr, testitem_timeout::Real, retries::Int, verbose_results::Bool, debug::Int, report::Bool, logs::Symbol)
function _runtests(shouldrun, paths, nworkers::Int, nworker_threads::String, worker_init_expr::Expr, testitem_timeout::Real, retries::Int, verbose_results::Bool, debug::Int, report::Bool, logs::Symbol)
# Don't recursively call `runtests` e.g. if we `include` a file which calls it.
# So we ignore the `runtests(...)` call in `test/runtests.jl` when `runtests(...)`
# was called from the command line.
Expand Down
10 changes: 10 additions & 0 deletions test/integrationtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -668,4 +668,14 @@ end
@test count("No Captured Logs", captured.output) == 1
end

if isdefined(Base.Threads, :nthreadpools)
@testset "Worker and nworker_threads argument" begin
test_file_path = joinpath(TEST_FILES_DIR, "_nworker_threads_test.jl")
results = encased_testset(()->runtests(test_file_path; nworkers=1, nworker_threads="3,2"))
@test n_passed(results) == 2
end
else
@warn "Skipping tests with interactive threadpool support which requires Julia Version v1.9+" VERSION
end

end # integrationtests.jl testset
28 changes: 28 additions & 0 deletions test/internals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -219,4 +219,32 @@ end
@test _error_message(fail, ti) == "Test failed at unknown:42"
end

@testset "_validated_nworker_threads" begin
auto_cpus = string(Base.Sys.CPU_THREADS)

@test ReTestItems._validated_nworker_threads(1) == "1"
@test_throws ArgumentError ReTestItems._validated_nworker_threads(0)
@test_throws ArgumentError ReTestItems._validated_nworker_threads(-1)

@test ReTestItems._validated_nworker_threads("1") == "1"
@test ReTestItems._validated_nworker_threads("auto") == auto_cpus
@test_throws ArgumentError ReTestItems._validated_nworker_threads("0")
@test_throws ArgumentError ReTestItems._validated_nworker_threads("-1")
@test_throws ArgumentError ReTestItems._validated_nworker_threads("1auto")
@test_throws ArgumentError ReTestItems._validated_nworker_threads("1,")

if isdefined(Base.Threads, :nthreadpools)
@test ReTestItems._validated_nworker_threads("1,1") == "1,1"
@test ReTestItems._validated_nworker_threads("2,1") == "2,1"
@test ReTestItems._validated_nworker_threads("1,2") == "1,2"
@test ReTestItems._validated_nworker_threads("auto,1") == "$auto_cpus,1"
@test ReTestItems._validated_nworker_threads("1,auto") == "1,1"
@test ReTestItems._validated_nworker_threads("auto,auto") == "$auto_cpus,1"
@test_throws ArgumentError ReTestItems._validated_nworker_threads("1,-1")
@test_throws ArgumentError ReTestItems._validated_nworker_threads("0,0")
@test_throws ArgumentError ReTestItems._validated_nworker_threads("0,1")
@test_throws ArgumentError ReTestItems._validated_nworker_threads("0,auto")
end
end

end # internals.jl testset
6 changes: 6 additions & 0 deletions test/testfiles/_nworker_threads_test.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This will only be called from a Julia version that supports interactive threadpool
@testitem "Was spawned with 3,2 threads" begin
using .Threads
@test nthreads() == 3
@test nthreads(:interactive) == 2
end

2 comments on commit f00d702

@Drvi
Copy link
Collaborator Author

@Drvi Drvi commented on f00d702 May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JuliaRegistrator
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: JuliaRegistries/General/84254

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if the Julia TagBot GitHub Action is installed, or can be done manually through the github interface, or via:

git tag -a v1.4.3 -m "<description of version>" f00d70266478ac86a3c4f344556243420075e212
git push origin v1.4.3

Please sign in to comment.