Help understanding allocation on scalar function and possible ways to avoid it


#1
  1. Can someone kindly explain me why the following function allocates memory? Is there a way to avoid it? On my machine it produces 14 allocations using inputs of Float64s (on Julia 6.1).
julia> using BenchmarkTools

julia> function energydistr_scalar(t11::T,t22::T,t33::T,t12::T,t13::T,t23::T,
                                           d11::T,d22::T,d33::T,d12::T,d13::T,d23::T,
                                           w12::T,w13::T,w23::T) where {T<:Number}

                        ɛ = t11 * d11 + t22 * d22 + t33 * d33 + 2.0*(t12 * d12 + t13*d13 + t23*d23)

                        dir11 = (d11*t11+d12*t12+d13*t13-t12*w12-t13*w13) - ɛ/3.
                        dir22 = (d12*t12+d22*t22+d23*t23+t12*w12-t23*w23) - ɛ/3.
                        dir33 = (d13*t13+d23*t23+d33*t33+t13*w13+t23*w23) - ɛ/3.
                        dir12 = 0.5*(d11*t12+d12*t11+d12*t22+d13*t23+d22*t12+d23*t13+t11*w12-t13*w23-t22*w12-t23*w13)
                        dir13 = 0.5*(d11*t13+d12*t23+d13*t11+d13*t33+d23*t12+d33*t13+t11*w13+t12*w23-t23*w12-t33*w13)
                        dir23 = 0.5*(d12*t13+d13*t12+d22*t23+d23*t22+d23*t33+d33*t23+t12*w13+t13*w12+t22*w23-t33*w23)

                       return ε,dir11,dir22,dir33,dir12,dir13,dir23
                     end
energydistr_scalar (generic function with 1 method)

julia> @benchmark energydistr_scalar(1.,2.,3.,4.,5.,5.,6.,7.,2.,8.,10.,11.,32.,23.,12.)
BenchmarkTools.Trial:
  memory estimate:  224 bytes
  allocs estimate:  14
  --------------
  minimum time:     102.095 ns (0.00% GC)
  median time:      106.017 ns (0.00% GC)
  mean time:        124.833 ns (6.61% GC)
  maximum time:     1.772 μs (83.59% GC)
  --------------
  samples:          10000
  evals/sample:     929

My real usage of this calculation is the following function:

julia> function energydistr_part!(t11::T,t22::T,t33::T,t12::T,t13::T,t23::T,
                             d11::T,d22::T,d33::T,d12::T,d13::T,d23::T,
                             w12::T,w13::T,w23::T,
                             dir11::T,dir22::T,dir33::T,dir12::T,dir13::T,dir23::T,
                             ɛ::T) where {T<:Vector{<:Number}}

         @inbounds for i in 1:length(d11)
           ɛ[i] = t11[i] * d11[i] + t22[i] * d22[i] + t33[i] * d33[i] + 2.0*(t12[i] * d12[i] + t13[i]*d13[i] + t23[i]*d23[i])

           dir11[i] = (d11[i]*t11[i]+d12[i]*t12[i]+d13[i]*t13[i]-t12[i]*w12[i]-t13[i]*w13[i]) - ɛ[i]/3.
           dir22[i] = (d12[i]*t12[i]+d22[i]*t22[i]+d23[i]*t23[i]+t12[i]*w12[i]-t23[i]*w23[i]) - ɛ[i]/3.
           dir33[i] = (d13[i]*t13[i]+d23[i]*t23[i]+d33[i]*t33[i]+t13[i]*w13[i]+t23[i]*w23[i]) - ɛ[i]/3.
           dir12[i] = 0.5*(d11[i]*t12[i]+d12[i]*t11[i]+d12[i]*t22[i]+d13[i]*t23[i]+d22[i]*t12[i]+d23[i]*t13[i]+t11[i]*w12[i]-t13[i]*w23[i]-t22[i]*w12[i]-t23[i]*w13[i])
           dir13[i] = 0.5*(d11[i]*t13[i]+d12[i]*t23[i]+d13[i]*t11[i]+d13[i]*t33[i]+d23[i]*t12[i]+d33[i]*t13[i]+t11[i]*w13[i]+t12[i]*w23[i]-t23[i]*w12[i]-t33[i]*w13[i])
           dir23[i] = 0.5*(d12[i]*t13[i]+d13[i]*t12[i]+d22[i]*t23[i]+d23[i]*t22[i]+d23[i]*t33[i]+d33[i]*t23[i]+t12[i]*w13[i]+t13[i]*w12[i]+t22[i]*w23[i]-t33[i]*w23[i])
         end
         return nothing
       end
energydistr_part! (generic function with 1 method)

julia> input = [rand(512) for i = 1:22];

julia> @benchmark energydistr_part!(input...)
BenchmarkTools.Trial:
  memory estimate:  112.00 KiB
  allocs estimate:  7168
  --------------
  minimum time:     60.250 μs (0.00% GC)
  median time:      62.518 μs (0.00% GC)
  mean time:        74.095 μs (5.25% GC)
  maximum time:     1.343 ms (83.13% GC)
  --------------
  samples:          10000
  evals/sample:     1

Which produces 14*length(d11) allocations. And since I using it with Arrays with lengths around 1024^3 I am already almost out of memory…


#2

This is fixed on 0.7. I think it has something to do with the length of your terms. A quick check seems to confirm this: just delete enough terms on all lines and the allocations go away. I think as a work-around you can use temporary variable.


#3

https://discourse.julialang.org/t/allocations-in-large-function/7559/2?u=kristoffer.carlsson


#4

That was it :smile:.
I’m ashamed that in my look-up I failed to find the answer which was posted just yesterday :sweat_smile: