# Understanding allocations in GeometryBasics.jl

I am currently using GeometryBasics.jl for a project. While optimizing the code, I noticed lots of memory allocations that hinders performance. Some of them I could figure it out but this one I cannot. Can somebody help me understanding why in the following test code there is one allocation. The code is really trivial and I was expecting no allocation. I am using version 1.6.2.

``````julia> using GeometryBasics, BenchmarkTools

julia> function tt2(p::Point3)
p*p + p*p + p*p
end
tt2 (generic function with 1 method)

julia> a = Point3{Float64}(1,1,1)
3-element Point3{Float64} with indices SOneTo(3):
1.0
1.0
1.0

julia> @btime tt2(a)
20.325 ns (1 allocation: 16 bytes)
3.0
``````

Thanks,

Pere

Interpolate your variables into benchmark tools macros, with `\$`:

``````@btime tt2(\$a)
``````

Your `tta` funciton is just math on `Float64` - there’s nothing to allocate. So it’s the global variable that is causing those allocations. Interpolating the variable moves it to the scope of the benchmark.

Thanks. I didn’t know. Is there an equivalent for `@time`?

``````julia> @time tt2(a)
0.000004 seconds (1 allocation: 16 bytes)
3.0
``````

Now that I understand that just math functions should not allocate, I found that looping on existing and preallocated data structures does allocate. See the example:

``````using GeometryBasics, BenchmarkTools

function mod2(p::Point3)
p*p + p*p + p*p
end

struct Triangle
a::Point3
b::Point3
c::Point3
end
function mod2(t::Triangle)
mod2(t.a) + mod2(t.b) + mod2(t.c)
end

struct Polygone
triangles::Vector{Triangle}
end
function mod2(p::Polygone)
sum = 0.
for t in p.triangles
sum += mod2(t)
end
sum
end

a = Point3{Float64}(0,0,0)
b = Point3{Float64}(1,0,0)
c = Point3{Float64}(0,1,0)
d = Point3{Float64}(0,0,1)
p = Polygone([Triangle(a,b,c),Triangle(a,b,d),Triangle(a,c,d), Triangle(b,c,d)])

@btime mod2(\$p)
374.458 ns (20 allocations: 320 bytes)
9.0
``````

Is there a way to avoid these allocations? Thanks.

What happens if you define `Triangle` as

``````struct Triangle{T}
a::Point3{T}
b::Point3{T}
c::Point3{T}
end
``````

That will make this code type stable.

If something simple like that is allocating, its usually because your code isn’t type stable. To add to oscars example, also `Polygone` `triangles` field will still have the abstract type `Vector{Triangle}`

Use a type parameter instead of an abstract typed field:

``````struct Polygone{T<:Vector{<:Triangle}}
triangles::T
end
``````

Or:

``````struct Polygone{T<:Triangle}}
triangles::Vector{T}
end
``````

You can check type stability of your funciton calls with the `@code_warntype` macro.

Thanks very much! Adding the type parameter `T` to `Triangle` and `Polygone` the allocations disappear.

``````struct Triangle{T}
a::Point3{T}
b::Point3{T}
c::Point3{T}
end

struct Polygone{T}
triangles::Vector{Triangle{T}}
end
``````
1 Like