-
-
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
invoke
d calls: record invoke signature in backedges
#46010
Conversation
Out of curiosity, why do we add backedges from |
#45934 introduced some conflicts on this PR. I will update this PR to resolve the conflicts. |
I think all the niggling issues have been fixed, and it even fixes a genuine invalidation bug that's been lurking in 1.8 (see f591258). Assuming CI passes, this seems ready for review ❤️ or a merge. |
Doctest failure should have been fixed in #46021. I think the rest are unrelated. |
Don't merge yet, we still need other changes. In particular, (1) we need |
e8cf7a9
to
9274f87
Compare
I rebased & squashed, and now the second tiny commit fixes (2), i.e., this now seems to solve the use cases for which it was intended. The third implements I think this is ready to merge, pending the results from CI. I would love a review but will merge soon in any case. |
As far as I can tell none of these failures are related. |
I've also run some benchmarks to see if there are any load-time regressions. This represents a pair of runs (shown is centroid ± half-width) on three different Julia versions. tl/dr: everything is fine, if anything this is an improvement. Load time
There seem to be no regressions for this PR compared to master, and possibly a benefit. (It's not impossible because load time depends a lot on backedge insertion, and present/absence of methodinstances in the cache affects this.) Sadly, at some point master got much slower at loading packages 😢, but that has nothing to do with this PR. Identifying the cause and fixing it is work for another PR and day. TTFX
Also a win here (not quite sure what happened in the case of ModelingToolkit on master). GLMakie is not quite in the realm of "tolerable" but we are getting there! This is with a |
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 also should teach jl_method_table_insert, in its direct call to invalidate_backedges
, to ignore edges that aren't changed, due to the new invoke info
src/dump.c
Outdated
k = 0; | ||
while (k < nlive) { | ||
k = get_next_backedge(milive->backedges, k, &invokeTypes2, &belive2); | ||
if (belive == belive2 && invokeTypes == invokeTypes2) { |
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.
jl_egal?
src/dump.c
Outdated
@@ -2470,7 +2543,7 @@ static void jl_insert_backedges(jl_array_t *list, jl_array_t *targets) | |||
int32_t idx = idxs[j]; | |||
jl_value_t *callee = jl_array_ptr_ref(targets, idx * 2); | |||
if (jl_is_method_instance(callee)) { | |||
jl_method_instance_add_backedge((jl_method_instance_t*)callee, caller); | |||
jl_method_instance_add_backedge((jl_method_instance_t*)callee, NULL, caller); |
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.
This should also need the invoke
-types for the backedge too (sometimes)?
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.
Ah, I guess we need to expand targets
list
to include the invokesig?
This allows a MethodInstance to store dispatch tuples as well as other MethodInstances among their backedges. The motivation is to properly handle invalidation with `invoke`, which allows calling a less-specific method and thus runs afoul of our standard mechanisms to detect "outdated" dispatch. Additionally: - provide backedge-iterators for both C and Julia that abstracts the specific storage mechanism. - fix a bug in the CodeInstance `relocatability` field, where methods that only return a constant (and hence store `nothing` for `inferred`) were deemed non-relocatable. - fix a bug in which #43990 should have checked that the method had not been deleted. Tests passed formerly simply because we weren't caching external CodeInstances that inferred down to a `Const`; fixing that exposed the bug. This bug has been exposed since merging #43990 for non-`Const` inference, and would affect Revise etc.
This mimics an `invoke` call
Co-authored-by: Jameson Nash <vtjnash@gmail.com>
e620c90
to
c9c87c1
Compare
Encode the `invokesig` in `ext_targets` so it gets cached to disk.
c9c87c1
to
5aaf76d
Compare
I think this can be merged if all tests pass (they do locally). This has become quite the intrusive change, and I no longer think this is appropriate for backporting, at least not until it's lived on master for quite some time (and most likely, not at all). I discussed this with @vchuravy and he kindly removed the backport-1.8 label. Just letting folks know this is aligned with my own views. |
This updates to the logging format used by the most recent nightly build of Julia (1.9). While there has been a lot of churn in this area, there are reasons to hope that we're entering a period of stability: there are no known "holes" in our coverage after resolving the `invoke` issues (JuliaLang/julia#46010 and fixup PRs that came later), and the subsequent major rewrite of the invalidation logic (JuliaLang/julia#46920) suggests this format may have some durability.
This updates to the logging format used by the most recent nightly build of Julia (1.9). While there has been a lot of churn in this area, there are reasons to hope that we're entering a period of stability: there are no known "holes" in our coverage after resolving the `invoke` issues (JuliaLang/julia#46010 and fixup PRs that came later), and the subsequent major rewrite of the invalidation logic (JuliaLang/julia#46920) suggests this format may have some durability. Co-authored-by: Rik Huijzer <rikhuijzer@pm.me>
This updates to the logging format used by the most recent nightly build of Julia (1.9). While there has been a lot of churn in this area, there are reasons to hope that we're entering a period of stability: there are no known "holes" in our coverage after resolving the `invoke` issues (JuliaLang/julia#46010 and fixup PRs that came later), and the subsequent major rewrite of the invalidation logic during deserialization (JuliaLang/julia#46920) suggests this format may have some durability. Co-authored-by: Rik Huijzer <rikhuijzer@pm.me>
This includes only the changes to `dump.c` for this change, but excludes the functional part of the change (except for the additional bugfixes mentioned below). ORIGINAL COMMIT TEXT: This fixes a long-standing issue with how we've handled `invoke` calls with respect to method invalidation. When we load a package, we need to ask whether a given MethodInstance would be compiled in the same way now (aka, in the user's running session) as when the package was precompiled; in practice, the way we do that is to test whether the dispatches would be to the same methods in the current world-age. `invoke` presents special challenges because it allows the coder to deliberately select a different method than the one that would be chosen by ordinary dispatch; if there is no record of how this choice was made, it can look like it resolves to the wrong method and this can trigger invalidation. This allows a MethodInstance to store dispatch tuples as well as other MethodInstances among their backedges. Additionally: - provide backedge-iterators for both C and Julia that abstracts the specific storage mechanism. - fix a bug in the CodeInstance `relocatability` field, where methods that only return a constant (and hence store `nothing` for `inferred`) were deemed non-relocatable. - fix a bug in which #43990 should have checked that the method had not been deleted. Tests passed formerly simply because we weren't caching external CodeInstances that inferred down to a `Const`; fixing that exposed the bug. This bug has been exposed since merging #43990 for non-`Const` inference, and would affect Revise etc. Co-authored-by: Jameson Nash <vtjnash@gmail.com> (cherry picked from commits dd375e1, cb0721b, 9e39fe9)
This PR fixes a corner case in our current scheme for invalidating outdated methods when loading
.ji
files. What we want to do is test whether a given MethodInstance would be compiled in the same way now as when the package was precompiled; for efficiency, what we actually do is test whether the dispatches would be to the same methods in the current world-age. It turns out that we've long had a "hole" in our assessment: for calls made byinvoke
,it looks like an outdated method got called because the signature is not the most specific one (
f(::GenericType)
gets compiled for specializationf(::SpecificType)
, which looks like a wrong or outdated choice of method), and we have no record that a less-specific method was deliberately chosen viainvoke
. Incorrectly classifying this backedge as outdated triggers unnecessary invalidation, which propagates all the way up call chains; since we happen to have aninvoke
in our broadcasting infrastructure, it means that in practice this issue is much more significant than the relatively modest number ofinvoke
calls one finds in Base, because almost all code that uses broadcasting gets invalidated, and that's quite a lot of package code.This works by expanding the kinds of backedges to 3:
caller::MethodInstance
in(callee::MethodInstance).backedges
invoke
which record theinvokesig::Type, caller::MethodInstance
in(callee::MethodInstance).backedges
as a sequential pairMethodTable
storessignature, caller
pairs, wheresignature
stores what is known by inference about the types of the arguments.Thus the
invoke
d backedges are intermingled with traditional ones incallee.backedges
, but they have a format similar to what one finds inMethodTable
s.By storing
invokesig
we get a second chance to check whether the method is the one that would currently be chosen byinvokesig
rather than the signature of the generated specialization ofcallee
. Thus this should robustly fix the invalidation issue.Closes #45001