Looking at Constants.jl in Julia 0.3 and 0.4
Although it looks like you are using Julia 0.3, and these results mostly concern Julia 0.4, it also has the same problem, and the reason is the same as the unnecessary distribution of intermediate elements.
To get an idea of โโwhat is going on, you can enter methods(^) and list all the methods defined for implementing ^. There are a lot of them, so I will not list them, but the important thing is that the Julia file that implements them is specified, in which case it is Constants.jl .
Julia 0.3 vs. Julia 0.4
First time in July 0.3
julia> @time test1(10000000) elapsed time: 0.313772825 seconds (320393016 bytes allocated, 37.16% gc time)
In Julia 0.4, thanks to a better garbage collector, the problem is reduced, but still present.
julia> @time test1(10000000) 170.445 milliseconds (20000 k allocations: 305 MB, 6.94% gc time) julia> @time test2(10000000) 2.355 microseconds (4 allocations: 144 bytes)
When there is an abnormal number of distributions, always suspect type instabilities or time series.
definition ^ for pi
In particular, lines 70 through 72 define a general method for raising MathConst to power.
for op in Symbol[:+, :-, :*, :/, :^] @eval $op(x::MathConst, y::MathConst) = $op(Float64(x),Float64(y)) end
using ^ for e instead of pi
Note also that later this is a specialization for the constant e , and the new test, where pi is replaced by e, does not have the same problem.
julia> function test4(N) for i = 1:N x = e^4 end end test4 (generic function with 1 method)
run test4
julia> @time test4(10000000) 108.401 milliseconds (4 allocations: 144 bytes)
Convert Int to Float64
If Float is created from Int , then this will avoid a problem starting with Float .
julia> function test5(N) for i = 1:N x = pi^4.0 end end
what's happening
julia> @time test5(10000000) 65.430 milliseconds (4 allocations: 144 bytes)
define a new feature set
Finally, you can create a new set of functions (testing in this case) that specifically define Int as the second parameter to avoid casting. This is not the best approach due to the ambiguity that it introduces, but it is good for the test.
julia> for op in Symbol[:+, :-, :*, :/, :^] @eval $op(x::MathConst, y::Int64) = $op(Float64(x),y) end Warning: New definition ^(MathConst{sym}, Int64) at none:2 is ambiguous with: ^(MathConst{:e}, Integer) at constants.jl:122. To fix, define ^(MathConst{:e}, Int64) before the new definition.
and then re-create test1
julia> function test1(N) for i = 1:N x = pi^4 end end test1 (generic function with 1 method)
and then re-run
julia> @time test1(10000000) 2.757 microseconds (4 allocations: 144 bytes)
do the same for Julia 0.3
Same fix, but use float64 instead of float64
julia> for op in Symbol[:+, :-, :*, :/, :^] @eval $op(x::MathConst, y::Int64) = $op(float64(x),y) end
and finally override and re-run the test in Julia 0.3
julia> @time test1(10000000) elapsed time: 3.023e-6 seconds (80 bytes allocated)