-
-
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
Type parameterize Core.Box #53385
base: master
Are you sure you want to change the base?
Type parameterize Core.Box #53385
Conversation
Signed-off-by: uniment <[email protected]>
Example of performance difference between type-asserting box vs. type-parameterizing box: julia> VERSION
v"1.12.0-DEV.17"
julia> @btime let a::Int=0; for i=1:1000; a+=i end; ()->a+=1 end;
4.983 μs (970 allocations: 15.16 KiB)
julia> @btime let a=Core.Box{Int}(0); for i=1:1000; a.contents+=i end; ()->a.contents+=1 end;
4.400 ns (1 allocation: 16 bytes) (notice microseconds vs nanoseconds timing) |
In order for something like this to be a good idea it feels to me the compiler would actually have to produce typed |
Before: julia> @btime let a::Int=0; for i=1:1000; a+=i end; ()->a+=1 end;
5.000 μs (970 allocations: 15.16 KiB) After: julia> @btime let a::Int=0; for i=1:1000; a+=i end; ()->a+=1 end;
4.200 ns (1 allocation: 16 bytes) This works for typed boxed local captures. I don't yet have a good idea of how to make typed globals match this performance. Example: julia> a::Int = 0
@btime for i=1:1000; global a+=1 end
5.617 μs (1000 allocations: 15.62 KiB) |
Signed-off-by: uniment <[email protected]>
Signed-off-by: uniment <[email protected]>
Unfortunately, it seems this change introduces a semantic change because an julia> function func()
local a::Int
for i = 1:0
a += i
end
() -> a += 1
end;
julia> func();
julia> f = func();
julia> f()
ERROR: UndefVarError: `a` not defined in local scope
Suggestion: check for an assignment to a local variable that shadows a global of the same name.
Stacktrace:
[1] (::var"#40#41")()
@ Main ./REPL[22]:6
[2] top-level scope
@ REPL[25]:1
julia> f()
569707965 |
That's a good catch, and I think I have a fix. However, this semantic change I'm more worried about:
julia> function foo()
T = Int
a::T = 0
() -> a+=1
end
ERROR: UndefVarError: `T` not defined in `Main` This errors because in this PR, This can be fixed if I implement the following two changes:
Change (1) will be easy, but (2) would require a change in semantics: require Also, while exploring this issue, I found a bug in how lexical scoping on typed captures is currently handled:
julia> function bar()
T = Int
g = () -> a+=1
a::T = 0
g
end;
julia> g = bar()
g()
ERROR: UndefVarError: `T` not defined in `Main` (I rank the priority on this bug very low, as declaring a capture after its closure is bad juju anyway imo.) |
On second thought, there's no need for semantics to change if we do this:
Seems pretty involved though, might take a while. |
This edit aims to take a small step toward solving some of the issues in #15276.
There are performance optimizations that do not occur when
Box
accesses are merelytypeasserted
, which instead require the box to be type-parameterized (example).This edit type-parameterizes
Core.Box
, and then future improvements leveraging type annotations and inference can build on top of that.