Hi,
I’m implementing a frequency sweep algorithm. In each iteration, two reduced models are evaluated on a grid of candidate points. Since each candidate frequency is evaluated independently of the others, I can evaluate them in different tasks.
The issue is that the evaluations involve BLAS operations. I ran some tests, and in general, when I increase the number of tasks into which i split the candidates, I get slightly better perfomance when I set the number of BLAS threads to 1.
The pseudocode would look something like this:
function with_BLAS_num_threads(f::F,n::Integer=1) where F
previous=BLAS.get_num_threads()
previous==n && return f()
try
BLAS.set_num_threads(n)
return f()
finally
BLAS.set_num_threads(previous)
end
end
# I can use ChunkSplitters.jl
function pseudo_errors!(errors, candidates, E_r1, A_r1, B_r1, C_r1, E_r2, A_r2, B_r2, C_r2, Δf, nthreads)
n = length(candidates)
chunk_size = ceil(Int, n / nthreads)
tasks = map(1:nthreads) do t
Threads.@spawn begin
# allocate matrices
H1 = # ...
chunk = (t-1)*chunk_size+1 : min(t*chunk_size, n)
for idx in chunk
fi = candidates[idx]
# compute s1 and s2
eval_reduced_model!(H1, args1...) #
eval_reduced_model!(H2, args2...)
errors[idx] = # something
end
end
end
foreach(wait, tasks)
return errors
end
with_BLAS_num_threads(1) do
pseudo_errors!(errors, candidates, E_r1, A_r1, B_r1, C_r1, E_r2, A_r2, B_r2, C_r2, Δf, nthreads)
end
My main interest isn’t performance, since I can benchmark that and determine whether the trade off is worthwhile. My main concern is whether there are any issues with this type of pattern.
- Are there any side effects or issues that I might be overlooking?
- Is there a more convenient or suitable pattern for this type of problem?
I’m interested in hearing how people would approach this in Julia, and whether there are any unexpected issues with this pattern that I should be aware of.