# How to improve performance in nested loops

Hello,

I’m writing a function whose performance suffers because of a nested for-loop. Below is a simplified version of that function.

The function `f()` takes no arguments, and instantiates `vecvec` a vector of vectors of `Int64`, all of the same size. Then, looping from `i = 1` to `5`, for each element of `vecvec` an operation that involves a slice of that element, the `i` index and a random component is performed. If the result of such operation is positive, the result is added to the element of `vecvec`, else the element must be removed from `vecvec`.

Here is the code:

``````function f()

vecvec::Vector{Vector{Int64}}  = [collect(i:(i+10)) for i in 1:10000]
to_be_removed = Set{Int64}()

for i in 1:5

for (j,arr) in enumerate(vecvec)

diff::Int64 = rand(Int64) + sum(arr[i:i+5]) - i
diff>0 ? push!(arr,diff) : push!(to_be_removed,j)

end

vecvec = [arr for (k,arr) in enumerate(vecvec) if k ∉ to_be_removed]
empty!(to_be_removed)

end

return vecvec

end
``````

Current performance is:

``````julia> using BenchmarkTools
julia> @btime f();
1.600 ms (33882 allocations: 5.39 MiB)
``````

Would you know any way to make it faster ?

## Improvements

``````julia> @btime f();
1.096 ms (14871 allocations: 3.07 MiB)
``````
``````function f()

vecvec::Matrix{Int64} = hcat([collect(i:(i+10)) for i in 1:10000]...)

to_be_kept = Int64[]
new_row = Int64[]

for i in 1:5
for (j,arr) in enumerate(eachcol(vecvec))

diff::Int64 = rand(Int64) + sum(@view(arr[i:i+5])) - i

if diff > 0
push!(new_row,diff)
push!(to_be_kept,j)
end

end
vecvec = [@view(vecvec[:,to_be_kept]) ; new_row']
empty!(to_be_kept)
empty!(new_row)
end

return vecvec

end

``````

``````julia> @btime new_f();
1.062 ms (10065 allocations: 3.90 MiB)
``````
1 Like

use a view here: `sum(@view(arr[i:i+r]))`.

try to remove all allocations which are not completely on purpose.

3 Likes

Can you avoid having a vector of vectors, and resizing half of them? Perhaps if these are columns of a matrix, and you keep track of which to keep, and what to append, then at the end you can make a new matrix which has one more row.

3 Likes

This is about three times faster on my system:

``````function g!(vec, i)
sum = 0
length(vec) >= i + 5 && @inbounds for i0 in 1:6
sum += vec[i0+i-1]
end
diff = rand(Int) + sum - i
push!(vec, diff)
end

mapg!(vecvec, i) = map(vec -> g!(vec, i), vecvec)

function G!(vecvec)
for i in 1:5
mapg!(vecvec, i)
filter!(vec -> last(vec) <= 0, vecvec)
end
return vecvec
end

function f()
vecvec = [collect(i:(i+10)) for i in 1:10000]
G!(vecvec)
return vecvec
end
``````
2 Likes