Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate foreign threads into a :foreign threadpool #50912

Merged
merged 3 commits into from
Aug 21, 2023
Merged

Conversation

vchuravy
Copy link
Member

In separate conversation over the last few days with @maleadt and @gbaraldi,
we noticed that foreign threads (or the utility thread in #50880) were used
by the scheduler for unrelated workloads.

Here we separate out the notion of interactive from unassociated.
In particular for foreign threads we should return to the calling foreign code
as soon as possible and not become co-opted into running unrelated workloads.

@async still executes on the parent thread as usual.

@vchuravy vchuravy added multithreading Base.Threads and related functionality backport 1.9 Change should be backported to release-1.9 backport 1.10 Change should be backported to the 1.10 release labels Aug 14, 2023
@JeffBezanson
Copy link
Member

JeffBezanson commented Aug 14, 2023

In particular for foreign threads we should return to the calling foreign code as soon as possible and not become co-opted into running unrelated workloads.

Won't that only happen if the foreign thread yields though? During that time we might as well use it for other work.

I also don't really like having a special-case "threadpool that is not really a threadpool".

@vchuravy
Copy link
Member Author

Yeah I really don't like this as well. I think the question if the foreign thread is yielding
is not all that relevant. We want people to no reason about yield-points and they should be able
to use Julia functions fearlessly.

Part of the question is what are the semantics of @spawn/@async on a foreign thread,
where should these run?

During that time we might as well use it for other work.

The problem is that we don't have a real notion of fairness in the scheduler. So it is indeterminate when/if the foreign thread returns. The root task is marked as sticky so that helps a bit, but in particular in the case of the libuv worker thread we need
to execute Julia callbacks, but don't want to any other code.

In particular the comment here motivated me to differentiate between, not in a threadpool and in a threadpool.

return 0; // everything else uses threadpool 0 (though does not become part of any threadpool)

@JeffBezanson
Copy link
Member

the case of the libuv worker thread we need to execute Julia callbacks, but don't want to any other code.

That thread could be considered interactive, but also our own event loop thread is worthy of a special case!

@async should run on the thread that launches it, and @spawn arguably should use the :default pool by default. AFAICT, we currently don't grow the default pool when foreign threads are added? Given that, I guess this PR can be considered a bugfix since foreign threads can't really run random tasks anyway.

base/docs/basedocs.jl Outdated Show resolved Hide resolved
@gbaraldi
Copy link
Member

At least from the perspective of a user I would think that if I called into julia, it would run my function and return. At least as a default behaviour.

@vchuravy
Copy link
Member Author

I was also half thinking of introducing two different categories instead of :unassociated. E.g. :utility and :foreign,

@maleadt
Copy link
Member

maleadt commented Aug 14, 2023

During that time we might as well use it for other work.

My concern was that the user might have started Julia with, say, -t 2 for good reason, e.g. to avoid oversubscribing the system. IIUC, if some library then started additional threads (both Metal and CUDA use worker threads for asynchronous callbacks) and those are used to schedule Julia tasks, we might end up using more resources than intended.

@vchuravy
Copy link
Member Author

AFAICT, we currently don't grow the default pool when foreign threads are added?

Yeah, we do not. We currently associate them with the :interactive threadpool,
so they could steal from the interactive work-queue,but we don't grow the pool.

I think long-term we may want to make pools resizable, but that's a bigger more complicated change.

It might make sense to split utility/system threads out, and then we could turn these workloads into tasks for GC sweep, libuv polling, maybe finalizers? GC sweep and finalizers could definitly run on the same thread (except for the fact that we currently don't start one by default.)

@vchuravy vchuravy added the triage This should be discussed on a triage call label Aug 16, 2023
@vchuravy vchuravy changed the title Separate foreign and utility threads into a :unassociated threadpool Separate foreign threads into a :foreign threadpool Aug 18, 2023
@vchuravy vchuravy added merge me PR is reviewed. Merge when all tests are passing and removed triage This should be discussed on a triage call labels Aug 18, 2023
@gbaraldi gbaraldi merged commit 8be469e into master Aug 21, 2023
1 check passed
@gbaraldi gbaraldi deleted the vc-gb/threadpool branch August 21, 2023 13:06
@oscardssmith oscardssmith removed the merge me PR is reviewed. Merge when all tests are passing label Aug 21, 2023
KristofferC pushed a commit that referenced this pull request Aug 23, 2023
Co-authored-by: Gabriel Baraldi <[email protected]>
Co-authored-by: Dilum Aluthge <[email protected]>
(cherry picked from commit 8be469e)
KristofferC added a commit that referenced this pull request Oct 2, 2023
Backported PRs:
- [x] #48625 <!-- add replace(io, str, patterns...) -->
- [x] #48387 <!-- Improve documentation of sort-related functions -->
- [x] #48363 <!-- Revise sort.md and docstrings in sort.jl -->
- [x] #48977 <!-- Update SparseArrays.jl stdlib for SuiteSparse 7 -->
- [x] #50719 <!-- fix `CyclePadding(::DataType)` -->
- [x] #50694 <!-- inference: permit recursive type traits -->
- [x] #50860 <!-- Add `Base.get_extension` to docs/API -->
- [x] #50594 <!-- Disallow non-index Integer types in isassigned -->
- [x] #50802 <!-- Makes IntrusiveLinkedListSynchronized mutable to avoid
allocation on poptask -->
- [x] #50858 <!-- Add a `threadpool` parameter to `Channel` constructor
-->
- [x] #50874 <!-- Restrict COFF to a single thread when symbol count is
high -->
- [x] #50822 <!-- Add default method for setmodifiers! -->
- [x] #50730 <!-- Fix integer overflow in `isapprox` -->
- [x] #50850 <!-- Remove weird Rational dispatch and add pi functions to
list -->
- [x] #50809 <!-- Limit type-printing in MethodError -->
- [x] #50915 <!-- Add note the `Task` about sticky bit -->
- [x] #50929 <!-- when widening tuple types in tmerge, only widen the
complex parts -->
- [x] #50928 <!-- Bump JuliaSyntax to 0.4.6 -->
- [x] #50959 <!-- Update libssh2 patches -->
- [x] #50823 <!-- Make ranges more robust with unsigned indexes. -->
- [x] #48542 <!-- Add docs on task-specific buffering using
multithreading -->
- [x] #50912 <!-- Separate foreign threads into a :foreign threadpool
-->
- [x] #51010 <!-- Add ORIGIN to SuiteSparse rpath on Linux/FreeBSD -->
- [x] #50753 <!-- cat: remove unused promote_eltype methods that confuse
inference -->
- [x] #51027 <!-- Implement realloc accounting correctly -->
- [x] #51019 <!-- fix a case of potentially use of undefined variable
when handling error in distributed message processing -->
- [x] #51039 <!-- Revert "Optimize findall(f, ::AbstractArray{Bool})
(#42202)" -->
- [x] #51036 <!-- add missing invoke edge for nospecialize targets -->
- [x] #51042 <!-- inference: fix return_type_tfunc modeling of concrete
functions -->
- [x] #51114 <!-- Workaround upstream FreeBSD issue #272992 -->
- [x] #50892 <!-- Add `JL_DLLIMPORT` to `small_typeof` declaration -->
- [x] #51154 <!-- broadcast: use recursion rather than ntuple to map
over a tuple -->
- [x] #51153 <!-- fix debug typo in "add missing invoke edge for
nospecialize targets (#51036)" -->
- [x] #51222 <!-- Check again if the tty is open inside the IO lock -->
- [x] #51236 <!-- Add lock around uv_unref during init -->
- [x] #51243 <!-- GMP: Gracefully handle more overflows. -->
- [x] #51254 <!-- Ryu: make sure adding zeros does not overwrite
trailing dot -->
- [x] #51175 <!-- shorten stale_age for cachefile lock -->
- [x] #51300 <!-- fix method definition error for bad vararg -->
- [x] #51307 <!-- fix force-throw ctrl-C on Windows -->
- [x] #51303 <!-- ensure revising structs is safe -->
- [x] #51393 
- [x] #51403 

Need manual backport:
- [x] #51009 <!-- fix #50562, regression in `in` of tuple of Symbols -->
- [x] #51053 <!-- Bump Statistics stdlib -->
- [x] #51013 <!-- fix #50709, type bound error due to free typevar in
sparam env -->
- [x] #51305 <!-- reduce test time for rounding and floatfuncs -->

Contains multiple commits, manual intervention needed:
- [ ] #50663 <!-- Fix Expr(:loopinfo) codegen -->
- [ ] #51035 <!-- refactor GC scanning code to reflect jl_binding_t are
now first class -->
- [ ] #51092 <!-- inference: fix bad effects for recursion -->
- [x] #51247 <!-- Check if malloc has succeeded before incrementing gc
stats -->
- [x] #51294 <!-- use LibGit2_jll for LibGit2 library -->

Non-merged PRs with backport label:
- [ ] #51132 <!-- Handle `AbstractQ` in concatenation -->
- [x] #51029 <!-- testdefs: make sure that if a test set changes the
active project, they change it back when they're done -->
- [ ] #50919 <!-- Code loading: do the "skipping mtime check for stdlib"
check regardless of the value of `ispath(f)` -->
- [ ] #50824 <!-- Add some aliasing warnings to docstrings for mutating
functions -->
- [x] #50385 <!-- Precompile pidlocks: add to NEWS and docs -->
- [ ] #49805 <!-- Limit TimeType subtraction to AbstractDateTime -->
@KristofferC KristofferC removed the backport 1.10 Change should be backported to the 1.10 release label Oct 2, 2023
KristofferC pushed a commit that referenced this pull request Oct 11, 2023
Co-authored-by: Gabriel Baraldi <[email protected]>
Co-authored-by: Dilum Aluthge <[email protected]>
(cherry picked from commit 8be469e)
nalimilan pushed a commit that referenced this pull request Nov 5, 2023
Co-authored-by: Gabriel Baraldi <[email protected]>
Co-authored-by: Dilum Aluthge <[email protected]>
(cherry picked from commit 8be469e)
KristofferC added a commit that referenced this pull request Nov 7, 2023
Backported PRs:
- [x] #49357 <!-- Fix unclosed code fence in src/manual/methods.md -->
- [x] #50842 <!-- Avoid race conditions with recursive rm -->
- [x] #50858 <!-- Add a `threadpool` parameter to `Channel` constructor
-->
- [x] #50730 <!-- Fix integer overflow in `isapprox` -->
- [x] #50823 <!-- Make ranges more robust with unsigned indexes. -->
- [x] #50915 <!-- Add note the `Task` about sticky bit -->
- [x] #50989 <!-- fix incorrect results in `expm1(::Union{Float16,
Float32})` -->
- [x] #50912 <!-- Separate foreign threads into a :foreign threadpool
-->
- [x] #51019 <!-- fix a case of potentially use of undefined variable
when handling error in distributed message processing -->
- [x] #51222 <!-- Check again if the tty is open inside the IO lock -->
- [x] #51254 <!-- Ryu: make sure adding zeros does not overwrite
trailing dot -->
- [x] #51284 <!-- Avoid infinite loop when doing SIGTRAP in arm64-apple
-->
- [x] #51491 <!-- Throw clearer ArgumentError for strip with two string
args -->
- [x] #51531 <!-- fix `_tryonce_download_from_cache` (busybox.exe
download error) -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport 1.9 Change should be backported to release-1.9 multithreading Base.Threads and related functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants