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.
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.