Browse Source

Add interface for managing threads

pull/38/head
Olav Møyner 2 months ago
parent
commit
8be2e61ef8
  1. 7
      docs/src/api.md
  2. 44
      src/HYPRE.jl
  3. 4
      src/LibHYPRE.jl
  4. 8
      test/runtests.jl

7
docs/src/api.md

@ -6,6 +6,13 @@
HYPRE.Init HYPRE.Init
``` ```
## Threads
```@docs
HYPRE.set_nthreads()
HYPRE.nthreads()
```
## Matrix/vector creation ## Matrix/vector creation
```@docs ```@docs

44
src/HYPRE.jl

@ -10,27 +10,37 @@ export HYPREMatrix, HYPREVector
# Clang.jl auto-generated bindings and some manual methods # Clang.jl auto-generated bindings and some manual methods
include("LibHYPRE.jl") include("LibHYPRE.jl")
using .LibHYPRE using .LibHYPRE
using .LibHYPRE: @check using .LibHYPRE: @check, HYPRE_SetNumThreads, HYPRE_NumThreads
# Internal namespace to hide utility functions # Internal namespace to hide utility functions
include("Internals.jl") include("Internals.jl")
""" """
Init(; finalize_atexit=true) Init(; finalize_atexit=true, nthreads = 1)
Wrapper around `HYPRE_Initialize`. If `finalize_atexit` is `true` a Julia exit hook is added, Wrapper around `HYPRE_Initialize`. If `finalize_atexit` is `true` a Julia exit hook is added,
which calls `HYPRE_Finalize`. This method will also call `MPI.Init` unless MPI is already which calls `HYPRE_Finalize`. This method will also call `MPI.Init` unless MPI is already
initialized. initialized.
The optional argument `nthreads` can be used to set the number of OpenMP threads
HYPRE should use. The default is `1`, meaning no multithreading. See
[`set_nthreads`](@ref) for more details. Setting `threads` to `0` or a negative
value means that the number of threads will be controlled by hypre internally.
This will typically be equal to the maximum number of threads, or the value in
the ENV variable `OMP_NUM_THREADS`.
**Note**: This function *must* be called before using HYPRE functions. **Note**: This function *must* be called before using HYPRE functions.
""" """
function Init(; finalize_atexit = true) function Init(; nthreads = 1, finalize_atexit = true)
if !(MPI.Initialized()) if !(MPI.Initialized())
MPI.Init() MPI.Init()
end end
# TODO: Check if already initialized? # TODO: Check if already initialized?
HYPRE_Initialize() HYPRE_Initialize()
if nthreads > 0
set_nthreads(nthreads)
end
if finalize_atexit if finalize_atexit
# TODO: MPI only calls the finalizer if not exiting due to a Julia exeption. Does # TODO: MPI only calls the finalizer if not exiting due to a Julia exeption. Does
# the same reasoning apply here? # the same reasoning apply here?
@ -44,6 +54,34 @@ function Init(; finalize_atexit = true)
return nothing return nothing
end end
"""
set_nthreads(1) # Single OpenMP thread
set_nthreads(10) # Use up to 10 OpenMP threads
Set the number of OpenMP threads HYPRE should use internally on current process.
The default is `1`, meaning no multithreading. Setting it to a zero or a
negative value means that the number of threads will be unchanged.
**Note***: The number of threads can improve execution speed, but a large number
of threads can be detrimental to actual solver performance for some solvers
(e.g. parallel Gauss-Seidel smoothers).
"""
function set_nthreads(nt::Integer)
if nt > 0
nt = min(nt, Sys.CPU_THREADS)
HYPRE_SetNumThreads(nt)
end
return nthreads()
end
"""
n = threads()
Get the current number of OpenMP threads HYPRE is set to use on current process.
"""
function nthreads()
return HYPRE_NumThreads()
end
############### ###############
# HYPREMatrix # # HYPREMatrix #

4
src/LibHYPRE.jl

@ -19,6 +19,10 @@ function HYPRE_SetNumThreads(nt::HYPRE_Int)
return @ccall libHYPRE.hypre_SetNumThreads(nt::HYPRE_Int)::Ptr{Cvoid} return @ccall libHYPRE.hypre_SetNumThreads(nt::HYPRE_Int)::Ptr{Cvoid}
end end
function HYPRE_SetNumThreads(nt::Integer)
return HYPRE_SetNumThreads(HYPRE_Int(nt))
end
# Add manual methods for some ::Function signatures where the library wants function # Add manual methods for some ::Function signatures where the library wants function
# pointers. Instead of creating function pointers to the Julia wrappers we can just look # pointers. Instead of creating function pointers to the Julia wrappers we can just look
# up the pointer in the library and pass that. # up the pointer in the library and pass that.

8
test/runtests.jl

@ -29,6 +29,14 @@ end
@test H.parmatrix != HYPRE_ParCSRMatrix(C_NULL) @test H.parmatrix != HYPRE_ParCSRMatrix(C_NULL)
end end
@testset "Threads" begin
@test HYPRE.set_nthreads(1) == 1
@test HYPRE.set_nthreads(2) == 2
@test HYPRE.nthreads() == 2
@test HYPRE.set_nthreads(0) == 2
@test HYPRE.set_nthreads(1_000_000) == Sys.CPU_THREADS
end
@testset "HYPREMatrix(::SparseMatrixCS(C|R))" begin @testset "HYPREMatrix(::SparseMatrixCS(C|R))" begin
ilower, iupper = 4, 6 ilower, iupper = 4, 6
CSC = convert( CSC = convert(

Loading…
Cancel
Save