The allocation occurs for the simplified code posted in the
gist above even if the called function is defined as
function Jacobianvolume{T<:FESet2Manifold}(self::FEMMBase{T}, J::FFltMat,
loc::FFltMat, conn::FIntMat, N::FFltMat)::FFlt
return 1.0
end
The expansion is
Variables:
#self#::FEMMBaseModule.#Jacobianvolume
self::FEMMBaseModule.FEMMBase{FESetModule.FESetT3,FEMMBaseModule.#otherdimensionunity}
J::Array{Float64,2}
loc::Array{Float64,2}
conn::Array{Int64,2}
N::Array{Float64,2}
Body:
begin
return 1.0
end::Float64
Dispatch doesn’t propagate type info for keywords, so FESetT3 is typed as Any.
Here is the problematic code:
type FESetT3 <: FESet2Manifold
nfensperfe::FInt
conn::FIntMat
label::FIntVec
function FESetT3(; conn::FIntMat=[], label =zero(FInt))
const nfensperfe::FInt = 3
@assert (size(conn, 2) == nfensperfe) "Number of nodes per element mismatched"
# Needs to make a COPY of the input arrays
self = new(nfensperfe, deepcopy(conn), deepcopy(FInt[]))
return self
end
end
This is faster:
function FESetT3( conn::FIntMat=[], label =zero(FInt))
# etc.
I leave it for the experts to say whether the inference engine is working properly here. Thanks for the puzzle of the day.
2 Likes
Thank you very much dear Sir, this was bugging me no end.
But, how did you figure it out? Where could you see that there was a type instability? What did you do? Or was there something that bit you too?
Petr
This sort of thing has bit me before - keyword arguments are often tricky. In this case, profiling showed that the time was spent in the loop construct itself rather than the function called there, so I applied code_warntype
to run1()
, which showed the untyped argument femm
in the Jacobianvolume
call (hence the expensive logic), preceded by
fes::Any = $(Expr(:invoke, MethodInstance for (::Core.#kw#Type)(::Array{Any,1}, ::Type{FESetModule.FESetT3}), :($(QuoteNode(Type))), :($(Expr(:invoke, MethodInstance for vector_any(::Any, ::Vararg{Any,N} where N), :(Base.vector_any), :(:conn), :(conn)))), :(Driver.FESetT3))) # line 13:
femm::Any = (Driver.FEMMBase)(fes::Any)::Union{FEMMBaseModule.FEMMBase, FEMMBaseModule.FEMMBase{_,FEMMBaseModule.#otherdimensionunity} where _} # line 14:
which points to the constructor I am quoting in the edited version of my reply above.