I tested the performance of an array of tuples and structs in Julia 1.3.1 and 1.5.1 and am a bit confused about the results. There are eight separate times based on three choices: 1.3.1 vs 1.5.1, structs vs tuples, and mutable member vs no mutable members.
Briefly: 1.5.1 is much faster than 1.3.1 in the case of a mutable member for both structs and tuples. The timing results and code are below.
I have a question about this: For the 1.5.1 execution, the timing results imply that structs and tuples are not heap-allocated even when they contain a mutable member. How does the run-time system keep track of whether the underlying array [72., 31.] has any live pointers to it (for garbage collection)? Is there any “gotcha” in using this new feature?
julia> include("testtup1.jl")
WARNING: replacing module testtup1.
VERSION = 1.3.1
Test of tuple with mutable member
0.203990 seconds (25.00 M allocations: 762.940 MiB, 12.14% gc time)
Test of struct with mutable member
0.200921 seconds (25.00 M allocations: 762.940 MiB, 9.90% gc time)
Test of tuple with all immutable members
0.065874 seconds (7 allocations: 416 bytes)
Test of struct with all immutable members
0.048031 seconds (7 allocations: 416 bytes)
Main.testtup1
julia> include("testtup1.jl")
WARNING: replacing module testtup1.
VERSION = 1.5.1
Test of tuple with mutable member
0.058091 seconds (2 allocations: 176 bytes)
Test of struct with mutable member
0.056815 seconds (2 allocations: 176 bytes)
Test of tuple with all immutable members
0.060029 seconds (2 allocations: 208 bytes)
Test of struct with all immutable members
0.048437 seconds (2 allocations: 208 bytes)
Main.testtup1
module testtup1
struct Example{T}
a::T
b::Int
end
function multiple_push_pop_tup(u)
T = Tuple{typeof(u), Int}
x = Vector{T}()
resize!(x,5)
sum1 = 0.0
for k = 1 : 5_000_000
k1 = (k % 2) + 1
for i = 1 : 5
x[i]= (u,k1)
end
for i = 1 : 5
v = x[i]
sum1 += v[1][v[2]]
end
end
return x[2], sum1
end
function multiple_push_pop_struct(u)
T = Example{typeof(u)}
x = Vector{T}()
resize!(x,5)
sum1 = 0.0
for k = 1 : 5_000_000
k1 = (k % 2) + 1
for i = 1 : 5
x[i]= T(u,k1)
end
for i = 1 : 5
v = x[i]
sum1 += v.a[v.b]
end
end
return x[2], sum1
end
const w = [72., 31.]
multiple_push_pop_tup(w)
multiple_push_pop_struct(w)
const y = (72., 31.)
multiple_push_pop_tup(y)
multiple_push_pop_struct(y)
println("VERSION = ", VERSION)
println("Test of tuple with mutable member")
@time multiple_push_pop_tup(w)
println("Test of struct with mutable member")
@time multiple_push_pop_struct(w)
println("Test of tuple with all immutable members")
@time multiple_push_pop_tup(y)
println("Test of struct with all immutable members")
@time multiple_push_pop_struct(y)
end