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

Performance of invoke #9608

Closed
yuyichao opened this issue Jan 5, 2015 · 6 comments
Closed

Performance of invoke #9608

yuyichao opened this issue Jan 5, 2015 · 6 comments
Labels
performance Must go faster

Comments

@yuyichao
Copy link
Contributor

yuyichao commented Jan 5, 2015

The performance of invoke is very poor even though the compiler already get as much information about the types as a normal function call during typeinf (in the case when typeof is used).

yuyichao% cat invoke.jl 
#!/usr/bin/julia

function f(a::Any, b::Any)
    global c = a + b
end

function f(a::Integer, b::Integer)
    global c = a + b
end

function f(a::Int, b::Int)
    global c = a + b
end

macro timing(ex)
    quote
        println($(Expr(:quote, ex)))
        gc()
        @time for i in 1:10000000
            $(esc(ex))
        end
    end
end

function call_any()
    f(1.2, 3.4)
end

function call_integer()
    f(Int32(1), Int32(2))
end

function call_int()
    f(1, 2)
end

function invoke_any()
    invoke(f, (Float64, Float64), 1.2, 3.4)
end

function invoke_integer()
    invoke(f, (Int32, Int32), Int32(1), Int32(2))
end

function invoke_int()
    invoke(f, (Int, Int), 1, 2)
end

function invoke_any_int()
    invoke(f, (Any, Any), 1, 2)
end

function invoke_integer_int()
    invoke(f, (Integer, Integer), 1, 2)
end

@timing call_any()
@timing call_integer()
@timing call_int()
println()
@timing invoke_any()
@timing invoke_integer()
@timing invoke_int()
println()
@timing invoke_any_int()
@timing invoke_integer_int()
println()
yyc2:~/projects/explore/julia/invoke
yuyichao% ./invoke.jl 
call_any()
elapsed time: 0.131868854 seconds (160000000 bytes allocated, 38.68% gc time)
call_integer()
elapsed time: 0.035920124 seconds (0 bytes allocated)
call_int()
elapsed time: 0.036067468 seconds (0 bytes allocated)

invoke_any()
elapsed time: 1.406940598 seconds (320002368 bytes allocated, 6.81% gc time)
invoke_integer()
elapsed time: 1.128576377 seconds (2368 bytes allocated)
invoke_int()
elapsed time: 0.795989108 seconds (2368 bytes allocated)

invoke_any_int()
elapsed time: 1.141055905 seconds (1856 bytes allocated)
invoke_integer_int()
elapsed time: 1.116886941 seconds (1856 bytes allocated)

I guess the compiler is not doing anything special about invoke now and treating it as a normal function?

Test done on latest master as of yesterday. Shouldn't be high priority (although invoke is actually used in a few sparse matrises functions and I'm not sure how performance critical are they...).

@simonster
Copy link
Member

Ref #3440 ("inline invoke()")

@yuyichao
Copy link
Contributor Author

yuyichao commented Jan 5, 2015

Just got a (possibly stupid in some way) idea while writing this issue. If the stagedfunction can be specialized based on value of a parameter, and if which is implemented as #9589, it would be possible for a user defined stagedfunction version of invoke to compute the method to use at compute time. This would probably save the method lookup time although I'm not sure if julia can inline anonymous function call yet....

Doing it this way will likely have the issue when new method though... #265

@yuyichao
Copy link
Contributor Author

yuyichao commented Jan 5, 2015

....Sorry, I've glance through that huge list but apparently missed it...............

@yuyichao yuyichao mentioned this issue Jan 6, 2015
@vtjnash vtjnash added the performance Must go faster label Jan 7, 2015
yuyichao added a commit that referenced this issue Sep 11, 2016
yuyichao added a commit that referenced this issue Sep 12, 2016
yuyichao added a commit that referenced this issue Sep 14, 2016
yuyichao added a commit that referenced this issue Sep 25, 2016
yuyichao added a commit that referenced this issue Oct 9, 2016
yuyichao added a commit that referenced this issue Oct 9, 2016
@stevengj
Copy link
Member

stevengj commented Dec 8, 2016

Not only is invoke slow, but it also apparently produces a type-unstable result. e.g.

g(x,y::Number) = y
g(x::Number,y) = x
g(x::Number,y::Number) = invoke(g, (Any,Number), x, y)
@inferred g(3,4)
ERROR: return type Int64 does not match inferred return type Any
 in error(::String) at ./error.jl:21

I just got bitten by this. It is very tempting to use invoke to resolve method ambiguities (as in the above toy example), but I'm not willing to kill performance and type inference.

@yuyichao
Copy link
Contributor Author

yuyichao commented Dec 8, 2016

That's a fairly different issue....

yuyichao added a commit that referenced this issue Jan 9, 2017
yuyichao added a commit that referenced this issue Jan 9, 2017
@yuyichao
Copy link
Contributor Author

yuyichao commented Jan 9, 2017

Just doing issue browsing before merging the PR and noticed the comment above again.

@stevengj It's caused by #18444 (comment).
invoke with a tuple of types has not been inferrable ever since the tuple type overhaul (iirc). That signature will be deprecated soon and fixing the depwarn should make it inferrable on 0.4+ and optimized on 0.6.

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

No branches or pull requests

5 participants