4
votes

Julia has the very nice feature of having access to its own syntactic tree, which makes it easy to generate new functions programatically, but it's much slower than the normal Julia code.

For example:

julia> timing = @time for i in [1:100] tan(pi/2*rand()); end
elapsed time: 1.513e-5 seconds (896 bytes allocated)

julia> timing = @time for i in [1:100] x = pi/2*rand(); eval(:(tan(x))); end
elapsed time: 0.0080231 seconds (23296 bytes allocated)

julia> timing = @time for i in [1:100]  eval(:(tan(pi/2*rand()))); end
elapsed time: 0.017245327 seconds (90496 bytes allocated)

Is there a way to give to eval the same speed as the normal Julia code?

EDIT: I was able to slightly speed up eval using the precompile function, but that still not enough:

julia> tmp3 = :(sin(x))
:(sin(x))

julia> timing = @time for i in [1:100000] x = pi/2*rand(); eval(tmp3); end
elapsed time: 8.651145772 seconds (13602336 bytes allocated)

julia> precompile(tmp3,(Float64,Float64))

julia> timing = @time for i in [1:100000] x = pi/2*rand(); eval(tmp3); end
elapsed time: 8.611654016 seconds (13600048 bytes allocated)

EDIT2:

@Ivarne suggested me to provide details on my project. Well, I would like to use the meta-programming capabilities of Julia to calculate the symbolic derivatives and run them.

I wrote a function derivative(ex::Expr,arg::Symbol) that takes and expression and an argument, and returns a new expression that is the derivative of ex with respect to arg. Unfortunately, the resulting Expr takes too long to evaluate.

EDIT3: as a conclusion, the performances using @eval instead of eval:

julia> timing = @time for i in [1:100000] x = pi/2*rand(); @eval(tmp3); end
elapsed time: 0.005821547 seconds (13600048 bytes allocated)

tmp3 is still :(sin(x))

1
do you understand that this shouldn't be important in most applications? macro expansion (which is where you manipulate julia's ast) typically occurs at compile time, not run time. so this slows down compilation a little bit, but not a running program.andrew cooke
@andrewcooke Well, that was the point of my question. Can I do something like myExpression() = compile(:(tan(pi/2*rand()))) or myExpression(x) = compile(:(tan(x))) to create at run time a compiled object?S4M

1 Answers

7
votes

If you need speed, you shouldn't use eval, because it has to do lots of work to generate optimized fast code every time.

If you want to manipulate expressions, you should look at macros instead. They operate on expressions and return expressions that will be compiled once. See http://docs.julialang.org/en/latest/manual/metaprogramming/.

If you provide some details on your problem, and not only performance testing on eval, it will be easier to point you in the right direction. Making eval in julia faster is a project, not a question for StackOverflow.

Edit: There is already some of that functionality in Calculus.jl, and I think it will be best if you do something like:

myexpr = :(sin(x))
myexpr_dx = derivative(myxpr)
@eval myfun(x) = $myexpr
@eval myfun_dx(x) = $myexpr_dx 

So that you get a function you can evaluate instead of an expression. You can then do performance testing on myfun(x) and myfun_dx()