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

Invalidate methods when binding is typed/const-defined #54733

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

topolarity
Copy link
Member

@topolarity topolarity commented Jun 7, 2024

This allows for patterns like:

julia> function foo(N)
    x = nothing
    for i = 1:N
        x = bar(i)
    end
    return x
end

julia> foo(1_000_000_000)
ERROR: UndefVarError: `bar` not defined

not to suffer a tremendous performance regression because of the fact that foo was inferred with bar still undefined.

This invalidation is not required for correctness, but for performance reasons once the global is defined we'd like to invalidate the code anyway to get an improved inference result:

julia> bar(x) = 3x
bar (generic function with 1 method)

julia> foo(1_000_000_000) # w/o PR: > 30 seconds, w/ PR: < 1μs

Note: This is essentially an optimized implementation of the non-semantic portion of #54654 for the special case of untyped/undefined globals, and this should mostly be compatible with that PR. Compared to that change, this adds explicit edges so that invalidation can be significantly faster and bit more fine-grained.

TODO:

  • Add lock to jl_binding_edges_t to prevent corruption from concurrent access
  • Add additional tests for global vs. const invalidations and x-module bindings
  • Fix up binding->ty not to be reset on serialization (use the closed/open rules on type set instead)

This allows for patterns like:
```
julia> function foo(N)
    for i = 1:N
        x = bar(i)
    end
end

julia> foo(1_000_000_000)
ERROR: UndefVarError: `bar` not defined
```

not to suffer a tremendous performance regression because of the fact
that `foo` was inferred with `bar` still undefined.

Strictly speaking the original code remains valid, but for performance
reasons once the global is defined we'd like to invalidate the code
anyway to get an improved inference result.

```
julia> bar(x) = 3x
bar (generic function with 1 method)

julia> foo(1_000_000_000) # w/o PR: takes > 30 seconds
```
@topolarity topolarity force-pushed the ct/invalidate-undef-bindings branch from 38d10b6 to 6e90c55 Compare June 7, 2024 20:11
@nsajko nsajko added performance Must go faster types and dispatch Types, subtyping and method dispatch labels Jun 10, 2024
@Keno
Copy link
Member

Keno commented Jun 10, 2024

I would prefer to do this after #54654 which requires these semantics already and at which point it'll simply become a time/space tradeoff. Which direction to pick for the tradeoff is hard to know without benchmarking.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance Must go faster types and dispatch Types, subtyping and method dispatch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants