@code_warntype ODEProblem shows `Any`

I tried the example here and see what @code_warntype returns:

julia> using DifferentialEquations

julia> function lorenz(du,u,p,t)
        du[1] = 10.0*(u[2]-u[1])
        du[2] = u[1]*(28.0-u[3]) - u[2]
        du[3] = u[1]*u[2] - (8/3)*u[3]
       end
lorenz (generic function with 1 method)

julia> u0 = [1.0;0.0;0.0]
3-element Array{Float64,1}:
 1.0
 0.0
 0.0

julia> tspan = (0.0,100.0)
(0.0, 100.0)

julia> @code_warntype ODEProblem(lorenz,u0,tspan)
Variables:
  #self#::Type{DiffEqBase.ODEProblem}
  f::#lorenz
  u0::Array{Float64,1}
  tspan::Tuple{Float64,Float64}

Body:
  begin 
      return $(Expr(:invoke, MethodInstance for #ODEProblem#185(::Array{Any,1}, ::Type{T} where T, ::Function, ::Array{Float64,1}, ::Tuple{Float64,Float64}, ::Void), :(DiffEqBase.#ODEProblem#185), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), Array{Any,1}, 0, 0, 0))), :(#self#), :(f), :(u0), :(tspan), :(DiffEqBase.nothing)))
  end::Any

Under what circumstances will it return a type other than DiffEqBase.ODEProblem? If I embed it into some simulation code, it will return Any, would that affect performance?

Solving any ODE takes so much longer than the 10-100ns of a single dynamic dispatch that solve acts as a good function barrier here. I would be heavily surprised if that caused a performance difference anywhere (and if it did, just let block it)

Just so that the details are out there, the issue stems from the keyword argument use which gets added via the macro

https://github.com/JuliaDiffEq/DiffEqBase.jl/blob/master/src/problems/ode_problems.jl#L14

so that the remake function can utilize a keyword argument version of the constructor. However, Julia doesn’t optimize keyword arguments at all on v0.6 so that is where the lack of inference comes from. Additionally, there is one parameter which isn’t ever inferred which is isinplace, but you can just declare that your function is in place like ODEProblem{true}(lorenz,u0,tspan). If you took off the macro, this will be inferred, but the in-place checking + keyword argument handling is what causes the issue.

But again, if all you’re doing with it is calling solve on the ODE then there’s no performance hit. Though you do need to make sure you shield downstream usage because keyword argument problems mean that the solution isn’t inferred. In the vast majority of cases though, analyzing the solution’s return isn’t where the time is really spent so you’re fine, but if it happens to be, then just put a function barrier or a let block there. But this is all set to fix itself once kwargs specialize enough (and I think Julia v0.7 has “enough”?)

1 Like