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

Extra Cassette code doesn't compile away like it's supposed to? #84

Closed
NHDaly opened this issue Nov 15, 2018 · 4 comments
Closed

Extra Cassette code doesn't compile away like it's supposed to? #84

NHDaly opened this issue Nov 15, 2018 · 4 comments

Comments

@NHDaly
Copy link
Contributor

NHDaly commented Nov 15, 2018

I seem to recall you stating somewhere that you want more people "using Cassette and posting bugs", so here i go! :P

I've created and pushed up Cassertte.jl, and the more general Toggles.jl I used to create it. Thanks for your help with it!

It works, but I'm surprised and sad to see all this native code bloat! Am i doing something wrong there, or is this a legitimate issue with Cassette that still remains?

:D So much fun!

julia> @code_native @withCassertte 5+5
    .section    __TEXT,__text,regular,pure_instructions
; Function @withCassertte {
; Location: Cassertte.jl:35
    pushl   %ebp
    decl    %eax
    movl    %esp, %ebp
    incl    %ecx
    pushl   %edi
    incl    %ecx
    pushl   %esi
    incl    %ecx
    pushl   %ebp
    incl    %ecx
    pushl   %esp
    pushl   %ebx
    decl    %eax
    andl    $-32, %esp
    decl    %eax
    subl    $160, %esp
    decl    %eax
    movl    %esi, %ebx
    vxorps  %xmm0, %xmm0, %xmm0
    vmovaps %ymm0, 64(%esp)
    decl    %eax
    movl    $0, 96(%esp)
    decl    %eax
    movl    %ebx, 128(%esp)
    decl    %eax
    movl    $61493632, %eax         ## imm = 0x3AA5180
    addl    %eax, (%eax)
    addb    %al, (%eax)
    vzeroupper
    calll   *%eax
    decl    %ecx
    movl    %eax, %esi
    decl    %eax
    movl    $6, 64(%esp)
    decl    %ecx
    movl    (%esi), %eax
    decl    %eax
    movl    %eax, 72(%esp)
    decl    %eax
    leal    64(%esp), %eax
    decl    %ecx
    movl    %eax, (%esi)
    decl    %esp
    movl    16(%ebx), %esp
    decl    %eax
    movl    $61271328, %ebx         ## imm = 0x3A6ED20
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %eax
    movl    $139887888, %edi        ## imm = 0x8568510
    addl    %eax, (%eax)
    addb    %al, (%eax)
    calll   *%ebx
    decl    %ecx
    movl    %eax, %edi
    decl    %esp
    movl    %edi, 96(%esp)
    decl    %eax
    movl    $139887952, %edi        ## imm = 0x8568550
    addl    %eax, (%eax)
    addb    %al, (%eax)
    calll   *%ebx
    decl    %eax
    movl    %eax, %ebx
    decl    %eax
    movl    %ebx, 88(%esp)
; Function esc; {
; Location: essentials.jl:462
; Function Type; {
; Location: boot.jl:221
    decl    %eax
    movl    $187084000, %eax        ## imm = 0xB26ACE0
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %eax
    movl    %eax, 24(%esp)
    decl    %esp
    movl    %esp, 32(%esp)
    decl    %ecx
    movl    $61292176, %ebp         ## imm = 0x3A73E90
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %esp
    leal    24(%esp), %esp
    xorl    %edi, %edi
    movl    $2, %edx
    decl    %esp
    movl    %esp, %esi
    incl    %ecx
    calll   *%ebp
    decl    %eax
    movl    %eax, 80(%esp)
;}}
    decl    %eax
    movl    $187083952, %ecx        ## imm = 0xB26ACB0
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %eax
    movl    %ecx, 24(%esp)
    decl    %esp
    movl    %edi, 32(%esp)
    decl    %eax
    movl    $139888080, %ecx        ## imm = 0x85685D0
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %eax
    movl    %ecx, 40(%esp)
    decl    %eax
    movl    %ebx, 48(%esp)
    decl    %eax
    movl    %eax, 56(%esp)
    xorl    %edi, %edi
    movl    $5, %edx
    decl    %esp
    movl    %esp, %esi
    incl    %ecx
    calll   *%ebp
    decl    %eax
    movl    %eax, 80(%esp)
    decl    %eax
    movl    $187097240, %ecx        ## imm = 0xB26E098
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %eax
    movl    %ecx, 24(%esp)
    decl    %eax
    movl    $139888144, %ecx        ## imm = 0x8568610
    addl    %eax, (%eax)
    addb    %al, (%eax)
    decl    %eax
    movl    %ecx, 32(%esp)
    decl    %eax
    movl    %eax, 40(%esp)
    xorl    %edi, %edi
    movl    $3, %edx
    decl    %esp
    movl    %esp, %esi
    incl    %ecx
    calll   *%ebp
    decl    %eax
    movl    72(%esp), %ecx
    decl    %ecx
    movl    %ecx, (%esi)
    decl    %eax
    leal    -40(%ebp), %esp
    popl    %ebx
    incl    %ecx
    popl    %esp
    incl    %ecx
    popl    %ebp
    incl    %ecx
    popl    %esi
    incl    %ecx
    popl    %edi
    popl    %ebp
    retl
;}

julia> @code_native 5+5
    .section    __TEXT,__text,regular,pure_instructions
; Function + {
; Location: int.jl:53
    decl    %eax
    leal    (%edi,%esi), %eax
    retl
;}
; Function <invalid> {
; Location: int.jl:53
    nopw    %cs:(%eax,%eax)
;}
@NHDaly NHDaly changed the title Code doesn't compile away like it's supposed to Code doesn't compile away like it's supposed to? Nov 15, 2018
@NHDaly NHDaly changed the title Code doesn't compile away like it's supposed to? Extra Cassette code doesn't compile away like it's supposed to? Nov 15, 2018
@NHDaly
Copy link
Contributor Author

NHDaly commented Nov 15, 2018

My guess is that it can't do const folding due to these remaining ::Union{OverdubInstead, Int64} type instabilities? But i'm not very familiar with all of this! :)

julia> using Cassertte

julia> @code_warntype Cassertte.Toggles.toggle(Cassertte.CassertteSwitch(), +, 5,5)
Body::Int64
23 1 ── %1  = (getfield)(args, 1)::Int64                                                                                                            │
   │    %2  = (getfield)(args, 2)::Int64                                                                                                            │
   │    %3  = (Core.tuple)(%1, %2)::Tuple{Int64,Int64}                                                                                              │
   │    %4  = (Base.sle_int)(1, 1)::Bool                                                                                                            │╻╷╷╷╷╷╷╷  #toggle#2
   └───       goto #3 if not %4                                                                                                                     ││┃││││││   Type
   2 ── %6  = (Base.sle_int)(1, 0)::Bool                                                                                                            │││┃││││││   #ToggleCtx#1
   └───       goto #4                                                                                                                               ││││┃││││     Type
   3 ──       nothing4 ┄─ %9  = φ (#2 => %6, #3 => false)::Bool                                                                                                       │││││┃│││      isempty
   └───       goto #6 if not %9                                                                                                                     ││││││┃││       iterate
   5 ──       invoke Base.getindex(()::Tuple{}, 1::Int64)                                                                                           │││││││┃│        iterate
   └───       $(Expr(:unreachable))                                                                                                                 ││││││││┃         iterate
   6 ──       goto #8                                                                                                                               │││││││││
   7 ──       $(Expr(:unreachable))                                                                                                                 │││││││││
   8 ┄─       goto #9                                                                                                                               ││││││││
   9 ──       goto #10                                                                                                                              ││││││╻         iterate
   10 ─       goto #11                                                                                                                              ││││││
   11 ─       goto #12                                                                                                                              │││││
   12 ─       goto #13                                                                                                                              ││││
   13 ─       goto #14                                                                                                                              │││
   14%21 = %new(getfield(Toggles, Symbol("##3#4")){Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},typeof(+),Tuple{Int64,Int64}}, $(QuoteNode(Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}())), +, %3)::getfield(Toggles, Symbol("##3#4")){Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}},typeof(+),Tuple{Int64,Int64}}
   └───       goto #16 if not true                                                                                                                  ││╻         #3
   15nothing16 ─       goto #18 if not true                                                                                                                  │││
   17nothing18 ─       goto #20 if not true                                                                                                                  │││
   19nothing20 ─       goto #22 if not true                                                                                                                  │││
   21nothing22 ─       goto #24 if not true                                                                                                                  │││
   23nothing24 ─       goto #26 if not true                                                                                                                  │││
   25%33 = Core.getfield::typeof(getfield)                                                                                                       │││
   └─── %34 = (%33)(%21, :args)::Tuple{Int64,Int64}                                                                                                 │││╻╷╷       overdub
   26%35 = φ (#25 => %34, #24 => $(QuoteNode(Cassette.OverdubInstead())))::Union{OverdubInstead, Tuple{Int64,Int64}}                             │││%36 = π (%35, Tuple{Int64,Int64})                                                                                                           │││
   └───       goto #32 if not true                                                                                                                  │││
   27%38 = Core._apply::typeof(Core._apply)                                                                                                      ││││╻         apply_args
   │    %39 = (%38)(tuple, %36)::Tuple{Int64,Int64}                                                                                                 │││││
   │    %40 = (getfield)(%39, 1)::Int64                                                                                                             │││╻         overdub
   │    %41 = (getfield)(%39, 2)::Int64                                                                                                             ││││
   └───       goto #29 if not true                                                                                                                  ││││╻         +
   28%43 = Base.add_int::Core.IntrinsicFunction                                                                                                  │││││
   └─── %44 = (%43)(%40, %41)::Int64                                                                                                                │││││╻╷╷       overdub
   29%45 = φ (#28 => %44, #27 => $(QuoteNode(Cassette.OverdubInstead())))::Union{OverdubInstead, Int64}                                          │││││%46 = π (%45, Int64)                                                                                                                        │││││
   └───       goto #30                                                                                                                              │││││
   30%48 = π (%46, Int64)                                                                                                                        │││╻         overdub
   └───       goto #31                                                                                                                              ││││
   31nothing32%51 = φ (#31 => %48, #26 => $(QuoteNode(Cassette.OverdubInstead())))::Union{OverdubInstead, Int64}                                          │││%52 = π (%51, Int64)                                                                                                                        │││
   └───       goto #33                                                                                                                              │││
   33 ─       goto #34                                                                                                                              ││
   34return %52                                                                                                                            │

julia>

@NHDaly
Copy link
Contributor Author

NHDaly commented Nov 15, 2018

I've also opened NHDaly/Cassertte.jl#1 to track any changes needed in my code.

Haha maybe I should consider a different name, just that one single r difference is actually pretty tricky to read... lol

@jrevels
Copy link
Collaborator

jrevels commented Nov 15, 2018

The idea is that there should be no "de facto overhead" from contextual code execution using Cassette.

Using your example (also using code_llvm since it's very hard to accurately draw conclusions from code_native):

julia> using Cassette

julia> Cassette.@context Ctx
Cassette.Context{nametype(Ctx),M,P,T,B} where B<:Union{Nothing, IdDict{Module,Dict{Symbol,BindingMeta}}} where P<:Cassette.AbstractPass where T<:Union{Nothing, Tag} where M

julia> @code_llvm 5 + 5

; Function +
; Location: int.jl:53
define i64 @"julia_+_35546"(i64, i64) {
top:
  %2 = add i64 %1, %0
  ret i64 %2
}

julia> f(x, y) = Cassette.overdub(Ctx(), +, x, y)
f (generic function with 1 method)

julia> @code_llvm f(5,5)

; Function f
; Location: REPL[4]:1
define i64 @julia_f_36037(i64, i64) {
top:
; Function +; {
; Location: int.jl:53
; Function overdub; {
; Location: /Users/jarrettrevels/.julia/dev/Cassette/src/overdub.jl:437
; Function macro expansion; {
; Location: /Users/jarrettrevels/.julia/dev/Cassette/src/overdub.jl:403
; Function fallback; {
; Location: /Users/jarrettrevels/.julia/dev/Cassette/src/context.jl:439
; Function call; {
; Location: /Users/jarrettrevels/.julia/dev/Cassette/src/context.jl:441
  %2 = add i64 %1, %0
;}}}}}
  ret i64 %2
}

As you can see, there's no performance overhead here for a "blank" context (note that there are definitely remaining edge cases, e.g. #71).

Of course, Cassette obviously can't make any performance guarantees about extra instrumentation inserted by context authors, e.g. I could use Cassette to insert a sleep between every function call if I wanted. In other words: Cassette can't do anything to prevent a context author's transformation from producing slow code.

I'm down to help fix any perf issues in downstream code, though, so let's continue discussion at NHDaly/Cassertte.jl#1. And, of course, if we find any upstreamable issues, that'd be a bonus! 🙂

@jrevels jrevels closed this as completed Nov 15, 2018
@NHDaly
Copy link
Contributor Author

NHDaly commented Dec 4, 2018

Hey, sorry I didn't respond for forever.

Okay cool gotcha! yes your explanation makes 100% sense. Thanks!! :) I'll move the discussion over there now then. :) Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants