-
Notifications
You must be signed in to change notification settings - Fork 1
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
Port EscapeAnalysis to Core.Compiler with Optimization #3
base: master
Are you sure you want to change the base?
Conversation
A status report of this PR: after disabling the My goal is first to observe the First we verify the result using
As we expected, the %1 is marked as We use the following code to observe the flag on C++ side (see below), but it never triggers, notice here we don't need to use Revise, we just start the REPL compiled using this PR's code.
|
src/llvm-alloc-opt.cpp
Outdated
printf("llvm-alloc-opt: find a metadata tag %p Function %p size %d\n", orig, &F, sz); | ||
} | ||
} | ||
if (use_info.escaped && !has_metadata_tag) { |
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.
Main changes here!
A status report of the latest progress: I find the instruction will make the However, this leads to an abort error:
cc @vtjnash |
It is unfortunate that it seems not to have unwind info for abort yet (Apple may have a fix in the next release), but catching that happen in lldb will likely show you which |
So EscapeAnalysis.jl has a serious performance problem, which appears only in bootstrapping. I made some inspections using the following `print` debug: > within `find_escapes!` ```julia if length(argtypes) > 0 Core.println(argtypes[1], " ", length(argtypes), " ", nstmts) end ``` ... and it seems like the performance of `find_escapes!` will be really awful when there is a large number of statements, say, `nstmts > 100`. The worse case I confirmed so far happens when analyzing `construct_ssa!(::CodeInfo, ::IRCode, ::DomTree, ::Any, ::Vector{Any})`, where I got the print `Core.Const(val=Core.Compiler.construct_ssa!) 182 4262`, and it took more than 100 sec on my machine (!!!). Note that `find_escapes!` works on after-inlining IR, so we often such many statements. The interesting property is, this performance problem seems really specific to bootstrapping. I confirmed that `find_escapes!` runs in 0.34 sec when I enabled it later using Revise. ```julia julia> @time code_typed(Core.Compiler.construct_ssa!, (Core.Compiler.CodeInfo, Core.Compiler.IRCode, Core.Compiler.DomTree, Any, Vector{Any})); ... Core.Const(val=Core.Compiler.setindex!) 4 5 Core.Const(val=Core.Compiler.construct_ssa!) 182 4262 0.342626 seconds (723.68 k allocations: 177.828 MiB, 15.69% gc time, 99.94% compilation time) ```
fix performance problem in bootstrapping
…RLie/julia into th3/port-to-core-compiler
This comment has been minimized.
This comment has been minimized.
Like this? @vchuravy
|
What's the LLVM for no_escape? And does it run? |
the LLVM for
Given this, I think it's inlined inside |
Yeah we knew what type it had and forwarded it... I was hoping to construe
a scenario where we didn't know during codegen, but type inference would
determine the value to be non-escaping.
My worry is that we then would try to access the type tag (which is stored
in front of the heap allocated object) but since we stack allocated it we
would access invalid memory.
…On Sun, Aug 15, 2021, 19:21 Xuanda Yang ***@***.***> wrote:
the LLVM for f_no_escape
julia> @code_llvm f_no_escape(Ref("foo"))
; @ REPL[4]:1 within `f_no_escape`
; Function Attrs: sspstrong
define nonnull {}* @japi1_f_no_escape_153({}* %0, {}** %1, i32 %2) #0 {
top:
%3 = alloca {}**, align 8
store volatile {}** %1, {}*** %3, align 8
ret {}* inttoptr (i64 4772411712 to {}*)
}
Given this, I think it's inlined inside g, am I correct?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABDO2S4MC3KHZYDAMK5F6DT47ZPZANCNFSM5ASCBAMA>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
Can the escape analysis look through Base.inferencebarrier?
…On Sun, Aug 15, 2021, 19:46 Valentin Churavy ***@***.***> wrote:
Yeah we knew what type it had and forwarded it... I was hoping to construe
a scenario where we didn't know during codegen, but type inference would
determine the value to be non-escaping.
My worry is that we then would try to access the type tag (which is stored
in front of the heap allocated object) but since we stack allocated it we
would access invalid memory.
On Sun, Aug 15, 2021, 19:21 Xuanda Yang ***@***.***> wrote:
> the LLVM for f_no_escape
>
> julia> @code_llvm f_no_escape(Ref("foo"))
> ; @ REPL[4]:1 within `f_no_escape`
> ; Function Attrs: sspstrong
> define nonnull {}* @japi1_f_no_escape_153({}* %0, {}** %1, i32 %2) #0 {
> top:
> %3 = alloca {}**, align 8
> store volatile {}** %1, {}*** %3, align 8
> ret {}* inttoptr (i64 4772411712 to {}*)
> }
>
> Given this, I think it's inlined inside g, am I correct?
>
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub
> <#3 (comment)>, or
> unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AABDO2S4MC3KHZYDAMK5F6DT47ZPZANCNFSM5ASCBAMA>
> .
> Triage notifications on the go with GitHub Mobile for iOS
> <https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
> or Android
> <https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
> .
>
|
With the below example, I think the analysis pass can look through the
|
@vchuravy is suggesting something like this: julia> @noinline f(x) = typeof(x.contents)
julia> @code_llvm f(Core.Box(3))
define nonnull {}* @japi1_f_366({}* %0, {}** %1, i32 %2) #0 {
top:
%3 = alloca {}**, align 8
store volatile {}** %1, {}*** %3, align 8
%4 = bitcast {}** %1 to {}***
%5 = load {}**, {}*** %4, align 8
; ┌ @ Base.jl:42 within `getproperty`
%6 = load atomic {}*, {}** %5 unordered, align 8
%.not = icmp eq {}* %6, null
br i1 %.not, label %fail, label %pass
fail: ; preds = %top
call void @jl_throw({}* inttoptr (i64 140632140761280 to {}*))
unreachable
pass: ; preds = %top
; └
%7 = bitcast {}* %6 to i64*
%8 = getelementptr inbounds i64, i64* %7, i64 -1
%9 = load atomic i64, i64* %8 unordered, align 8
%10 = and i64 %9, -16
%11 = inttoptr i64 %10 to {}*
ret {}* %11
} |
Then in this case, |
Where does it escape from? It can't be the typeof call, since the compiler / runtime sometimes injects though just for convenience |
In your example, On current master of
|
This comment has been minimized.
This comment has been minimized.
Yeah I've noticed the difference and have updated the result in the comment |
I suppose because it could throw? Does the |
I think anything involving in a |
The throwness check depends on minimum number of initialized fields, and that's why Jameson asked whether |
I am still pretty confused about this. By "depends on minimum number of initialized fields" do you mean the check will produce different results given the different numbers of fields inside the struct (for example, For jameson's comment, are we looking for something like this:
|
check the type of |
Oh yeah I added a signature to it now it becomes:
|
Sorry, only have sporadic internet here.
What about:
```
@noinline function ***@***.***(x))
y = Base.inferencebarrier(x)
T = typeof(y)
@show T
return nothing
end
```
So if escape analysis can look at this function see that x is non-escaping,
that would be great!
Important here is that the inferred type of y is Any, but the runtime type
is of course something concrete.
Now codegen runs and on the caller side we optimize `x`, and on the caller
side we generate code that might assume that x is heap allocated, and has a
type tag stored in front of it.
The way to fix this would be for IPO based heap2stack to also store the
typetag in front.
…On Mon, Aug 16, 2021, 15:55 Xuanda Yang ***@***.***> wrote:
With the below example, I think the analysis pass can look through the
Base.inferencebarrier call
julia> @noinline f_no_escape(x) = Base.inferencebarrier(nothing)
f_no_escape (generic function with 1 method)
julia> @analyze_escapes f_no_escape(Ref("hah"))
typeof(f_no_escape)(_2::Base.RefValue{String} ↑)
1 ◌ 1 ─ return nothing
julia> @noinline f_no_escape(x) = (Base.inferencebarrier(nothing); x)
f_no_escape (generic function with 1 method)
julia> @analyze_escapes f_no_escape(Ref("hah"))
typeof(f_no_escape)(_2::Base.RefValue{String} ↑)
1 ◌ 1 ─ return _2
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#3 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABDO2RC326O44E4XK3L4NLT5EKFBANCNFSM5ASCBAMA>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email>
.
|
…tional` (JuliaLang#42434) Otherwise, in rare cases, we may see this sort of weird behavior: ```julia julia> @eval edgecase(_) = $(Core.Compiler.InterConditional(2, Int, Any)) edgecase (generic function with 1 method) julia> code_typed((Any,)) do x edgecase(x) ? x : nothing end 1-element Vector{Any}: CodeInfo( 1 ─ goto #3 if not $(QuoteNode(Core.InterConditional(2, Int64, Any))) 2 ─ return x 3 ─ return Main.nothing ) => Any julia> code_typed((Any,)) do x edgecase(x) ? x : nothing end 1-element Vector{Any}: CodeInfo( 1 ─ goto #3 if not $(QuoteNode(Core.InterConditional(2, Int64, Any))) 2 ─ %2 = π (x, Int64) └── return %2 3 ─ return Main.nothing ) => Union{Nothing, Int64} ```
Escape analysis is super useful for a variety of reasons. I came here from JuliaLang#7721, where better escape analysis means better automatic closing of resources. Has this work made its way into JuliaLang/julia yet? |
It's already merge into the Julia base. We aren't enabling it (nor using it for any optimizations) at this moment because of a latency problem though. xref: JuliaLang#43800 |
No description provided.