Iβm trying to choose the fastest among the following 3 functions:
using Test, BenchmarkTools
function Mut!(x::Array{Int64,2},y::Array{Int64,1})
map!(z->z*2,x,x)
y .= vec(reduce(+,x,dims=1))
end
function MutRet(x::Array{Int64,2})
map!(z->z*2,x,x)
vec(reduce(+,x,dims=1))
end
function Ret(x::Array{Int64,2})
x2 = map(z->z*2,x)
y = vec(reduce(+,x2,dims=1))
return x2,y
end
@testset "mutate and return" begin
x = Int64.(fill(5,2,10))
y = fill(5,10)
Mut!(x,y)
@test all(x .== 10)
@test all(y .== 20)
x = fill(5,2,10)
y = MutRet(x)
@test all(x .== 10)
@test all(y .== 20)
x = Int64.(fill(5,2,10))
x,y = Ret(x)
@test all(x .== 10)
@test all(y .== 20)
end
x = Int64.(fill(5,2,10))
y = fill(5,10)
@code_warntype Mut!(x,y)
x = fill(5,2,10)
@code_warntype MutRet(x)
x = Int64.(fill(5,2,10))
@code_warntype Ret(x)
x = Int64.(fill(5,2,10))
y = fill(5,10)
@btime Mut!(x,y);
x = fill(5,2,10)
@btime MutRet(x);
x = Int64.(fill(5,2,10))
@btime Ret(x);
type-stability
Variables
#self#::Core.Compiler.Const(Mut!, false)
x::Array{Int64,2}
y::Array{Int64,1}
#321::var"#321#322"
Body::Array{Int64,1}
1 β (#321 = %new(Main.:(var"#321#322")))
β %2 = #321::Core.Compiler.Const(var"#321#322"(), false)
β Main.map!(%2, x, x)
β %4 = (:dims,)::Core.Compiler.Const((:dims,), false)
β %5 = Core.apply_type(Core.NamedTuple, %4)::Core.Compiler.Const(NamedTuple{(:dims,),T} where T<:Tuple, false)
β %6 = Core.tuple(1)::Core.Compiler.Const((1,), false)
β %7 = (%5)(%6)::NamedTuple{(:dims,),Tuple{Int64}}
β %8 = Core.kwfunc(Main.reduce)::Core.Compiler.Const(Base.var"#reduce##kw"(), false)
β %9 = (%8)(%7, Main.reduce, Main.:+, x)::Array{Int64,2}
β %10 = Main.vec(%9)::Array{Int64,1}
β %11 = Base.broadcasted(Base.identity, %10)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(identity),Tuple{Array{Int64,1}}}
β %12 = Base.materialize!(y, %11)::Array{Int64,1}
βββ return %12
Variables
#self#::Core.Compiler.Const(MutRet, false)
x::Array{Int64,2}
#323::var"#323#324"
Body::Array{Int64,1}
1 β (#323 = %new(Main.:(var"#323#324")))
β %2 = #323::Core.Compiler.Const(var"#323#324"(), false)
β Main.map!(%2, x, x)
β %4 = (:dims,)::Core.Compiler.Const((:dims,), false)
β %5 = Core.apply_type(Core.NamedTuple, %4)::Core.Compiler.Const(NamedTuple{(:dims,),T} where T<:Tuple, false)
β %6 = Core.tuple(1)::Core.Compiler.Const((1,), false)
β %7 = (%5)(%6)::NamedTuple{(:dims,),Tuple{Int64}}
β %8 = Core.kwfunc(Main.reduce)::Core.Compiler.Const(Base.var"#reduce##kw"(), false)
β %9 = (%8)(%7, Main.reduce, Main.:+, x)::Array{Int64,2}
β %10 = Main.vec(%9)::Array{Int64,1}
βββ return %10
Variables
#self#::Core.Compiler.Const(Ret, false)
x::Array{Int64,2}
#325::var"#325#326"
x2::Array{Int64,2}
y::Array{Int64,1}
Body::Tuple{Array{Int64,2},Array{Int64,1}}
1 β (#325 = %new(Main.:(var"#325#326")))
β %2 = #325::Core.Compiler.Const(var"#325#326"(), false)
β (x2 = Main.map(%2, x))
β %4 = (:dims,)::Core.Compiler.Const((:dims,), false)
β %5 = Core.apply_type(Core.NamedTuple, %4)::Core.Compiler.Const(NamedTuple{(:dims,),T} where T<:Tuple, false)
β %6 = Core.tuple(1)::Core.Compiler.Const((1,), false)
β %7 = (%5)(%6)::NamedTuple{(:dims,),Tuple{Int64}}
β %8 = Core.kwfunc(Main.reduce)::Core.Compiler.Const(Base.var"#reduce##kw"(), false)
β %9 = (%8)(%7, Main.reduce, Main.:+, x2)::Array{Int64,2}
β (y = Main.vec(%9))
β %11 = Core.tuple(x2, y)::Tuple{Array{Int64,2},Array{Int64,1}}
βββ return %11
benchmarks
82.646 ns (3 allocations: 240 bytes)
74.559 ns (3 allocations: 240 bytes)
105.459 ns (6 allocations: 528 bytes)
I have a couple questions:
- why is MutRet faster than Ret?
- why is the number of allocations listed for MutRet is the same as Mut, even though MutRet needs to create the [additional] return value
vec(reduce(+,x,dims=1))
βedited original for several errors as pointed out in commentsβ