I made some experiments that helped me further understand both qualitative and quantitative behaviour of dynamic dispatch cost and method caches. So I thought I may as well add it to the collection. Have a look if you like.
I do not mean to suggest to do anything in a literal sense done in the code. In particular Val{n} and sum are just placeholders for some types and a function.
using Plots
valsum(::Val{x}) where x = Val(sum(x))
valsum(::Val{m1}, ::Val{m2}) where {m1,m2} = Val(m1+m2)
valsum(::Val{m1}, ::Val{m2}, ::Val{m3}, ::Val{m4}, ::Val{m5}, ::Val{m6}, ::Val{m7}, ::Val{m8}, ::Val{m9}, ::Val{m10}) where {m1,m2,m3,m4,m5,m6,m7,m8,m9,m10} = Val(m1+m2+m3+m4+m5+m6+m7+m8+m9+m10)
val_n(::Val{n}) where n = n
to_tuple(x::Vector{<:Val}) = Val(Tuple(val_n.(x)))
function foo2(v::Vector{<:Vector{Val}})
for x = v
valsum(x[1], x[2])
end
return nothing
end
function foo10(v::Vector{<:Vector{Val}})
for x = v
valsum(x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10])
end
return nothing
end
function bar2(v::Vector{<:Val})
for x = v
valsum(x)
end
return nothing
end
bar10(v) = bar2(v)
valselect(::Val{m}, x) where {m} = valsum(x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[10])
function foo10_sel(v::Vector{<:Vector{Val}})
for x = v
valselect(x[1], x)
end
return nothing
end
const vals = [Val(m) for m = 1:6]
const fcts = (foo2, foo10, bar2, bar10, foo10_sel)
const paras = Tuple((i, g) for i = fcts for g = (repeat, rand))
const k_range = 1:10
const times = []
for _ = paras
push!(times, zeros(length(k_range)))
end
const V = Array{Any,2}(undef, 2, length(fcts))
const ell = 1000
function test(r)
GC.gc()
for k = k_range
print("$k ")
# repeating pattern:
x2 = [rand(vals, 2) for _ = 1:k]
x10 = [rand(vals, 10) for _ = 1:k]
V[1, 1] = repeat(x2, Int(ceil(ell/k)))
V[1, 2] = repeat(x10, Int(ceil(ell/k)))
# random pattern:
V[2, 1] = rand(x2, ell)
V[2, 2] = rand(x10, ell)
for j = 1:4
V[j+4] = to_tuple.(V[j])
end
for j = 5:length(fcts)
V[1, j] = V[1, 2]
V[2, j] = V[2, 2]
end
q = collect(enumerate(paras))
for z = (r:length(paras), 1:(r-1)), (i, (f, _)) = q[z]
f(V[i])
# GC.gc() # avoid gc spikes during timed run
t = @timed f(V[i])
times[i][k] += t.time
end
end
end
test(1)
test(2)
test(3)
test(4)
test(5)
test(6)
test(7)
test(8)
test(9)
begin
p = plot()
fct_cols = (:orange, :red, :blue, :violet, :gray)
paras_style = Tuple((i, b) for i = fct_cols for b = (:solid, :dash))
for (i, ((fct, g), (color, linestyle))) = enumerate(zip(paras, paras_style))
str = "$fct, $g"
plot!(p, k_range[2:end], times[i][2:length(k_range)], label=str; linestyle, color)
end
xlabel!(p, "number of different type collections")
ylabel!(p, "time in seconds")
display(p)
end
