carstenbauer / ThreadPinning.jl

Readily pin Julia threads to CPU-threads
https://carstenbauer.github.io/ThreadPinning.jl/
MIT License
106 stars 7 forks source link

Feature request: temporary pinning (with do block) ? #81

Closed ederag closed 10 months ago

ederag commented 10 months ago

pinthreads is able to stabilize benchmark runs inside Pluto too, thanks ! It seems to play well with the new Pluto/Malt combination.

Yet it would be nice to encapsulate a block (e.g. a benchmark) inside pinthreads, leaving the rest of the notebook running normally.

For instance, defining

# `with_pinthreads` instead of just `pinthreads` to avoid piracy
function with_pinthreads(f::Function, args...; kwargs...)
    pinthreads(args...; kwargs...)
    result = f()
    unpinthreads()
    result
end

allows

with_pinthreads([0]) do
    @benchmark sin.(x) setup=(x = rand(10))
end

Would that be in the ThreadPinning package scope ? Of course it would be better to store/restore the previous thread pinning (unpinned, :core, ...) instead of just unpinthreads(), but I fail to see how to do that.

carstenbauer commented 10 months ago

I think that such a feature would be a nice addition.

Of course it would be better to store/restore the previous thread pinning (unpinned, :core, ...) instead of just unpinthreads(), but I fail to see how to do that.

That's doable. We can simply query and store the affinity mask of each thread at the beginning and then to restore it at the end. (see ThreadPinning.get_affinity_mask / ThreadPinning.uv_thread_getaffinity)

carstenbauer commented 10 months ago

@ederag, added in https://github.com/carstenbauer/ThreadPinning.jl/pull/82. Please try it out!

ederag commented 10 months ago

82 works perfectly, tested with Pluto v0.19.32,

tried in particular

unpinthreads()  # outer setup unpinned
with_pinthreads([10]) do
    # runs on the 11th CPU, as expected
    @benchmark sin.(x) setup=(x = rand(10))
end
# runs on a random CPU (tested several times), as expected
@benchmark sin.(x) setup=(x = rand(10))

pinthreads([0])  # outer setup pinned to the first CPU
with_pinthreads([10]) do
    # runs on the 11th CPU, as expected
    @benchmark sin.(x) setup=(x = rand(10))
end
# runs on the first CPU, as expected
@benchmark sin.(x) setup=(x = rand(10))

Thanks !

carstenbauer commented 10 months ago

Great, I'll tag a new release.

carstenbauer commented 10 months ago

BTW, @ederag, if you care about ThreadPinning.jl in Pluto, I always wanted to have nicer support for threadinfo in Pluto. I'm thinking of

Maybe you want to give that a try? :)

ederag commented 10 months ago

Sorry, I'd like to help but I'm not good enough at HTML display stuff.

And I do not see how to get Pluto reactive updates for mutations (see https://github.com/fonsp/Pluto.jl/issues/564). Actually the operating system might be allowed to move threads (if unpinned), so a periodic polling seems adequate ? Here is a Pluto notebook (start the clock to get periodic updates). Screenshot_20231114_093446

Pluto people on zulip or discourse do amazing things and would probably be more helpful.