How to avoid allocation when modifying a structure in a function

memory-allocation
#1

Dear All

I have a function which I need to make as efficient as possible.

The function takes many many inputs, and I have organised them into a structure in order to make the code more manageble and clean.

I have noticed that some times when within the function I modify the content of the structure pass to the function then some memory allocation happens, which slows down the code.

Here is a working example. Is there a way to avoid allocation while keep using a structure, or something similar, to group the inputs?

Thank you
Best
Francesco

using BenchmarkTools

mutable struct My_struct
	vector_1::AbstractVector
end

function my_function!(input::My_struct)
	input.vector_1[1] = 1 + input.vector_1[2]		# allocations occur here, I guess to manage the right hand side
	return nothing
end

# test

structure_1 = My_struct(ones(10))

@btime my_function!(structure_1)

I get

  63.500 ns (2 allocations: 32 bytes)
#2

I don’t know exactly where the allocations come from, but you are using two performance anti-patterns and removing those solves this in my testing.

First of all, in your code example, and also more generally in the situation you describe, there is no reason for the struct to be mutable. You seem to confuse mutable with const-ness from other languages. In Julia, you can absolutely modify the contents of vector_1 even if the struct is not mutable.

Secondly, you shouldn’t have abstract types like AbstractVector in your fields. It’s much better to parametrize.

Solving these two issues gives:

julia> struct My_struct_2{V}
               vector_1::V
       end

julia> function my_function!(input::My_struct_2)
               input.vector_1[1] = 1 + input.vector_1[2]                # allocations occur here, I guess to manage the right hand side
               return nothing
       end
my_function! (generic function with 2 methods)

julia> # test

       structure_2 = My_struct_2(ones(10))
My_struct_2{Array{Float64,1}}([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0])

julia> @btime my_function!(structure_2)
  11.556 ns (0 allocations: 0 bytes)

Do read the performance tips – it clearly describes this latter issue.

2 Likes
#3

Great, it works, thank you very much for the indications!
Best
Francesco