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

Ellide immutable allocation in some simple cases #15259

Merged
merged 1 commit into from
Mar 1, 2016
Merged

Conversation

carnaval
Copy link
Contributor

Extend tuple_elim_pass and getfield_elim_pass to handle immutable object allocations.

@andreasnoack

julia> immutable Diag; A :: Vector{Float64}; end
julia> *(d::Diag,M) = scale(d.A,M)
* (generic function with 142 methods)
julia> f(x,M) = Diag(x)*M
f (generic function with 1 method)
julia> code_typed(f,(Vector{Float64},Matrix{Float64}))
1-element Array{Any,1}:
 :($(Expr(:lambda, Any[symbol("#self#"),:x,:M], Any[Any[Any[symbol("#self#"),#f,0],Any[:x,Array{Float64,1},0],Any[:M,Array{Float64,2},0]],Any[],Any[Tuple{Int64,Int64}]], :(begin  # none, line 1: # none, line 1: # linalg/matmul.jl, line 42:
        GenSym(0) = (top(tuple))((Base.arraysize)(M::Array{Float64,2},1)::Int64,(Base.arraysize)(M::Array{Float64,2},2)::Int64)::Tuple{Int64,Int64} # array.jl, line 120:
        return (Base.LinAlg.scale!)((top(ccall))(:jl_new_array,(top(apply_type))(Core.Array,Float64,2)::Type{Array{Float64,2}},(top(svec))(Core.Any,Core.Any)::SimpleVector,Array{Float64,2},0,GenSym(0),0)::Array{Float64,2},x::Array{Float64,1},M::Array{Float64,2})::Array{Float64,2}
    end::Array{Float64,2}))))

no allocations

@tkelman
Copy link
Contributor

tkelman commented Feb 26, 2016

Any way of testing that it stays this way?

@andreasnoack andreasnoack mentioned this pull request Feb 27, 2016
@carnaval
Copy link
Contributor Author

@tkelman yep, I'll write those

About the 32 bit failure

Expression: besselj(-i,Float32(0)) == 0
Evaluated: NaN32 == 0

I'm trying to repro but apparently building a 32 bit version of julia is beyond me

@timholy
Copy link
Sponsor Member

timholy commented Feb 27, 2016

Something that initially confused me: "no allocations" means for the immutable wrapper, but the array output still gets allocation due to the call to jl_new_array.

Excited about this!

@carnaval
Copy link
Contributor Author

Yep sorry that was unclear. This requires the compiler to see both the allocation and every usage (getfield) so it needs a lot of inlining. It is useful for example to get rid of overhead for small wrapper structs such as enumerate :

julia> f(x) = (for (i,j) in enumerate(x); i; end)
f (generic function with 1 method)

julia> code_typed(f, (Vector{Int},))
1-element Array{Any,1}:
 :($(Expr(:lambda, Any[symbol("#self#"),:x], Any[Any[Any[symbol("#self#"),#f,0],Any[:x,Array{Int64,1},0],Any[symbol("#s1"),Tuple{Int64,Int64},2],Any[:i,Int64,18],Any[:j,Int64,18],Any[symbol("#s2"),Int64,2],Any[symbol("##n#9276"),Tuple{Int64,Int64},18]],Any[],Any[Enumerate{Array{Int64,1}},Tuple{Tuple{Int64,Int64},Tuple{Int64,Int64}},Tuple{Int64,Int64},Tuple{Int64,Int64},Tuple{Int64,Int64},Int64,Int64,Int64,Array{Int64,1},Tuple{Int64,Int64},Tuple{Int64,Int64},Int64,Int64,Int64,Int64]], :(begin  # none, line 1:
        GenSym(8) = x::Array{Int64,1}
        #s1 = (top(tuple))(1,1)::Tuple{Int64,Int64}
        2: 
        unless (Base.box)(Base.Bool,(Base.not_int)(((Base.getfield)(#s1::Tuple{Int64,Int64},2)::Int64 === (Base.box)(Int64,(Base.add_int)((Base.arraylen)(GenSym(8))::Int64,1)))::Bool)) goto 1 # iterator.jl, line 15:
        GenSym(5) = (Base.getfield)(#s1::Tuple{Int64,Int64},2)::Int64 # array.jl, line 234:
        GenSym(6) = (Base.arrayref)(GenSym(8),GenSym(5))::Int64
        GenSym(7) = (Base.box)(Int64,(Base.add_int)(GenSym(5),1)) # iterator.jl, line 16:
        GenSym(9) = (top(tuple))((Base.getfield)(#s1::Tuple{Int64,Int64},1)::Int64,GenSym(6))::Tuple{Int64,Int64}
        GenSym(10) = (top(tuple))((Base.box)(Int64,(Base.add_int)((Base.getfield)(#s1::Tuple{Int64,Int64},1)::Int64,1)),GenSym(7))::Tuple{Int64,Int64}
        GenSym(2) = GenSym(9)
        #s2 = 1
        GenSym(11) = (Base.getfield)(GenSym(2),1)::Int64
        GenSym(12) = (Base.box)(Int64,(Base.add_int)(1,1))
        i = GenSym(11)
        #s2 = GenSym(12)
        GenSym(13) = (Base.getfield)(GenSym(2),2)::Int64
        GenSym(14) = (Base.box)(Int64,(Base.add_int)(2,1))
        j = GenSym(13)
        #s2 = GenSym(14)
        #s1 = GenSym(10) # none, line 1:
        i::Int64
        3: 
        goto 2
        1: 
        0: 
        return
    end::Void))))

@yuyichao
Copy link
Contributor

The 32bit travis failure in the math test already shows up at least twice on master..

@tkelman
Copy link
Contributor

tkelman commented Feb 28, 2016

@simonbyrne I think you tweaked bessel in some way recently?

@simonbyrne
Copy link
Contributor

Hopefully this should be fixed by #15272. Sorry about that.

@carnaval carnaval force-pushed the ob/immalloc branch 4 times, most recently from 6ef3947 to a7490f5 Compare March 1, 2016 03:32
Extend tuple_elim_pass and getfield_elim_pass to handle immutable object allocations.
carnaval added a commit that referenced this pull request Mar 1, 2016
Ellide immutable allocation in some simple cases
@carnaval carnaval merged commit eb59d63 into master Mar 1, 2016
@carnaval carnaval deleted the ob/immalloc branch March 1, 2016 15:19
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

Successfully merging this pull request may close these issues.

5 participants