Why is in this function calling the getindex
method the second time slower?
This function (the smallest working example I could make) is a snippet of a bigger project I’m making on agent based models where I choose a random element and his neighbors and then I operate on the data associated to both.
function testing(
data::Vector{Vector{T}},
neighs::Vector{Vector{T}},
n_elements::Integer,
maxtime::Integer
) where {T<:Integer}
for _ in 1:maxtime
element_1 = rand(1:n_elements)
element_2 = rand(neighs[element_1])
data_1 = data[element_1]
data_2 = data[element_2]
end
end
n_elements = 1000
my_data = [rand(1:10, 10) for _ = 1:n_elements]
my_neighs = [rand(1:n_elements, 5) for _ = 1:n_elements]
@profview testing(my_data, my_neighs, n_elements, 1_000_000_000)
When profiling in VS Code I get the following profiling:
- 38%:
element_2 = rand(neighs[element_1])
- 31%:
element_1 = rand(1:n_elements)
- 21%:
data_2 = data[element_2]
- 5%:
data_1 = data[element_1]
This is the flame graph:
I would like to understand why this second call of the data vector of vector is much slower. Is it a problem in the profiler? This especially seems to happen in vector of vectors, and when I have the second element taken from another vector.
Thanks in advance for anyone that will help me!
Output of @code_warntype
MethodInstance for testing(::Vector{Vector{Int64}}, ::Vector{Vector{Int64}}, ::Int64, ::Int64)
from testing(data::Array{Vector{T}, 1}, neighs::Array{Vector{T}, 1}, n_elements::Integer, maxtime::Integer) where T<:Integer @ Main c:\Users\aless\My Drive\Dottorato\PhD Code\ABM\axelrod\julia\minimal_test.jl:1
Static Parameters
T = Int64
Arguments
#self#::Core.Const(testing)
data::Vector{Vector{Int64}}
neighs::Vector{Vector{Int64}}
n_elements::Int64
maxtime::Int64
Locals
@_6::Union{Nothing, Tuple{Int64, Int64}}
data_2::Vector{Int64}
data_1::Vector{Int64}
element_2::Int64
element_1::Int64
Body::Nothing
1 ─ %1 = (1:maxtime)::Core.PartialStruct(UnitRange{Int64}, Any[Core.Const(1), Int64])
│ (@_6 = Base.iterate(%1))
│ %3 = (@_6 === nothing)::Bool
│ %4 = Base.not_int(%3)::Bool
└── goto #4 if not %4
2 ┄ %6 = @_6::Tuple{Int64, Int64}
│ Core.getfield(%6, 1)
│ %8 = Core.getfield(%6, 2)::Int64
│ %9 = (1:n_elements)::Core.PartialStruct(UnitRange{Int64}, Any[Core.Const(1), Int64])
│ (element_1 = Main.rand(%9))
│ %11 = Base.getindex(neighs, element_1)::Vector{Int64}
│ (element_2 = Main.rand(%11))
│ (data_1 = Base.getindex(data, element_1))
│ (data_2 = Base.getindex(data, element_2))
│ (@_6 = Base.iterate(%1, %8))
│ %16 = (@_6 === nothing)::Bool
│ %17 = Base.not_int(%16)::Bool
└── goto #4 if not %17
3 ─ goto #2
4 ┄ return nothing