I’m experiencing performance issues when using Unitful arrays inside a structure. I don’t know how to specify the type so well, so the problem may be from the type definition.
Here is a simple example using a struct
and a function to compute the sum of an array. The version with Unitful is a lot slower and has many more allocations:
struct MyData1{T <: AbstractFloat}
arr1::Array{T, 3}
end
struct MyData2{T <: AbstractFloat}
arr1::Array{<: Unitful.Temperature{T}, 3}
end
function my_sum(data)
nx, ny, nz = size(data.arr1)
tmp = data.arr1[1] * 0
for k in 1:nz, j in 1:ny, i in 1:nx
tmp += data.arr1[i, j, k]
end
return tmp
end
function do_compute1()
nx, ny, nz = 10, 10, 200
arr1 = ones(Float64, (nx, ny, nz))
data = MyData1(arr1)
my_sum(data)
end
function do_compute2()
nx, ny, nz = 10, 10, 200
arr1 = ones(Float64, (nx, ny, nz))u"K"
data = MyData2(arr1)
my_sum(data)
end
Benchmarking do_compute1()
(no Unitful) and do_compute2()
(with Unitful) gives:
@btime do_compute1()
27.280 μs (2 allocations: 156.33 KiB)
@btime do_compute2()
1.801 ms (64409 allocations: 1.66 MiB)
Perhaps the problem is that I’m specifying Array{<: Unitful.Temperature{T}, 3}
, but how to specify a specific type of array (in this case, array of K, for a given type T)? If I use Array{Unitful.Temperature{T}, 3}
it won’t work. Since
julia> typeof(zeros(3, 3, 3)u"K")
Array{Quantity{Float64,𝚯,Unitful.FreeUnits{(K,),𝚯,nothing}},3}
I also tried
Array{Quantity{Float64,Unitful.𝚯,Unitful.FreeUnits{(Unitful.K,),Unitful.𝚯,nothing}},3}
but that doesn’t seem to match the type either. Bizarrely these types are not the same:
julia> typeof(zeros(3, 3, 3)u"K") == Array{Quantity{Float64,Unitful.𝚯,Unitful.FreeUnits{(Unitful.K,),Unitful.𝚯,nothing}},3}
false
Even though if I print them out they seem to be about the same.
Back to the actual question: how to declare Unitful arrays in struct
so that the type inference is not some generic array?