A plot of dynamic dispatch cost

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