-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Allow for :foreigncall to transition to GC safe automatically #49933
Conversation
Since we already have the trampoline stuff, what about adding a safepoint into every call into the julia runtime? Similar to the safepoint in JIT function calls? |
How would this affect packages that use CxxWrap or jlrs to provide access to C++ and Rust libraries, which call back into into Julia from foreign functions? |
All in Julia itself? Perhaps. All in all Julia packages? Definitely not! That would be a breaking change. |
Can you point at a for-instance @fingolfin? |
The not common but existing case is for julia code to call c code that calls julia runtime functions. |
@kpamnany any package using a JLL linking against I am not saying this is an impossible change, but only if there is a well thought out migration strategy that is coordinated with all stakeholders. But just saying "it probably won't affect that many packages, let's just do it", without a full analysis and without involving the community, repeats the "main" debacle. Let's not go there. Overall, I prefer "code that is not as fast as it could be but is correct" over "code that is perhaps a bit faster, or not, but will occasionally crash or produce garbage... A more viable alternative would be an opt-in solution -- but then of course many packages will miss this opportunity. A pity, but it wouldn't leave us worse than we are right now, new packages could benefit from it. (If we had something like Rust editions, then for "new" packages this could become the default, I guess...?) |
aca69d9
to
47a08bb
Compare
47a08bb
to
6fcef7c
Compare
Now is:
The safepoint emission at that point needs to be cleaner. @vtjnash that's probably closer to what it needs to be? |
Note for when this lands: we should redo JuliaLang/MbedTLS.jl#265. |
This allows the GC to run while potentially blocking in a CUDA library. To make this safe, callbacks into Julia should again transition to GC-unsafe mode. It should be reimplemented when JuliaLang/julia#49933 lands. Co-authored-by: Tim Besard <[email protected]>
6fcef7c
to
e007905
Compare
@gbaraldi I rebased this and confirmed that: @eval function put(msg)
cmsg = Base.cconvert(Cstring, msg)
ptr = Base.unsafe_convert(Cstring, cmsg)
$(Expr(:foreigncall, QuoteNode(:puts), Cint, Core.svec(Cstring), 0, true, QuoteNode(:ccall), :ptr, :cmsg))
end
|
This is missing some safepoints no? STATIC_INLINE int8_t jl_gc_state_set(jl_ptls_t ptls, int8_t state,
int8_t old_state)
{
assert(old_state != JL_GC_PARALLEL_COLLECTOR_THREAD);
assert(old_state != JL_GC_CONCURRENT_COLLECTOR_THREAD);
jl_atomic_store_release(&ptls->gc_state, state);
if (state == JL_GC_STATE_UNSAFE || old_state == JL_GC_STATE_UNSAFE)
jl_gc_safepoint_(ptls);
return old_state;
} |
I only posted an excerpt:
|
And yeah I was gonna say, the conditionality of the safepoint is probably a bit dumb, even in gc_state_set |
@gbaraldi I would prefer |
0ea64c0
to
699a949
Compare
72ed182
to
e1a8b94
Compare
@@ -404,9 +434,16 @@ Example using an external library: | |||
|
|||
The string literal could also be used directly before the function | |||
name, if desired `"libglib-2.0".g_uri_escape_string(...` | |||
|
|||
It's possible to declare the ccall as `gc_safe` by using the `gc_safe = true` option: | |||
@ccall gc_safe=true strlen(s::Cstring)::Csize_t |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚲 If gc_safe=false
is the default, perhaps marking a ccall
as gc_safe
could just be spelled like:
@ccall :gc_safe strlen(s::Cstring)::Csize_t
(similar to how the @atomic
and @spawn
and @assume_effects
macros take Symbols to control behaviour)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We hope to be able to flip the default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would that work (flipping the default)? What's the transition strategy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There isn't a firm strategy yet, right now anything using cfunction
/@ccallable
will transition correctly (this was done for foreign thread adoption) so the big issue is anything that uses the runtime. Already we have a trampoline in place and it may be feasible to add a transition check to that trampoline.
This would make calls into the runtime safe as well, but we wouldn't want to double transition for calls from Julia to the runtime, so we would need to manually mark those as gc_safe=false
.
If the trampoline strategy works we should be able to flip the switch without any correctness issues, but it may be inefficient due to frequent transition and double transitions.
ce14078
to
41ef0c4
Compare
2ebb73e
to
557119f
Compare
llvmpasses and windows tests are failing |
9c70ad2
to
8b252f8
Compare
@@ -4,6 +4,8 @@ Julia v1.12 Release Notes | |||
New language features | |||
--------------------- | |||
|
|||
* The `@ccall` macro can now take a `gc_safe` argument, that if set to true allows the runtime to run garbage collection concurrently to the `ccall` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably have been in HISTORY since you want it backported
This has been bouncing around as a idea for a while. One of the challenges around time-to-safepoint has been Julia code that is calling libraries. Since foreign code will not include safepoints we see increased latency when one thread is running a foreign-call and another wants to trigger GC. The open design question here is: - Do we expose this as an option the user must "opt-in", e.g. by using a keyword arg to `@ccall` or a specific calling-convetion. - Or do we turn this on for all ccall, except for Julia runtime calls. There is relativly little code outside the Julia runtime that needs to be "GC unsafe", exception are programs that directly use the Julia C-API. Incidentially `jl_adopt_thread` and `@cfunction`/`@ccallable` do the right thing and transition to "GC unsafe", regardless of what state the thread currently is in. I still need to figure out how to reliably detect Julia runtime calls, but I think we can switch all other calls to "GC safe". We should also consider optimizations that mark large regions of code without Julia runtime interactions as "GC safe" in particular numeric for-loops. Closes #57057 --------- Co-authored-by: Gabriel Baraldi <[email protected]> (cherry picked from commit 85458a0)
Backported PRs: - [x] #57346 <!-- lowering: Only try to define the method once --> - [x] #57341 <!-- bpart: When backdating replace the entire bpart chain --> - [x] #57381 <!-- staticdata: Set min validation world to require world --> - [x] #57357 <!-- Only implicitly `using` Base, not Core --> - [x] #57383 <!-- staticdata: Fix typo in recursive edge revalidation --> - [x] #57385 <!-- bpart: Move kind enum into its intended place --> - [x] #57275 <!-- Compiler: fix unsoundness of getfield_tfunc on Tuple Types --> - [x] #57378 <!-- print admonition for auto-import only once per module --> - [x] #57392 <!-- [LateLowerGCFrame] fix PlaceGCFrameReset for returns_twice --> - [x] #57388 <!-- Bump JuliaSyntax to v1.0.2 --> - [x] #57266 <!-- 🤖 [master] Bump the Statistics stdlib from d49c2bf to 77bd570 --> - [x] #57395 <!-- lowering: fix has_fcall computation --> - [x] #57204 <!-- Clarify mathematical definition of `gcd` --> - [x] #56794 <!-- Make `Pairs` public --> - [x] #57407 <!-- staticdata: corrected implementation of jl_collect_new_roots --> - [x] #57405 <!-- bpart: Also partition the export flag --> - [x] #57420 <!-- Compiler: Fix check for IRShow definedness --> - [x] #55875 <!-- fix `(-Inf)^-1` inconsistency --> - [x] #57317 <!-- internals: add _defaultctor function for defining ctors --> - [x] #57406 <!-- bpart: Ignore guard bindings for ambiguity purposes --> - [x] #49933 <!-- Allow for :foreigncall to transition to GC safe automatically -->
This has been bouncing around as a idea for a while.
One of the challenges around time-to-safepoint has been Julia code
that is calling libraries.
Since foreign code will not include safepoints we see increased latency
when one thread is running a foreign-call and another wants to trigger GC.
The open design question here is:
keyword arg to
@ccall
or a specific calling-convetion.There is relativly little code outside the Julia runtime that needs to be "GC unsafe",
exception are programs that directly use the Julia C-API. Incidentially
jl_adopt_thread
and
@cfunction
/@ccallable
do the right thing and transition to "GC unsafe", regardlessof what state the thread currently is in.
I still need to figure out how to reliably detect Julia runtime calls, but I think we can
switch all other calls to "GC safe". We should also consider optimizations that mark large
regions of code without Julia runtime interactions as "GC safe" in particular numeric
for-loops.
Closes #57057