Type stability of `quadgk`

Hi,

I am doing several calculations using QuadGK inside functions and I’m trying to optimize the performance of my code. Not sure if it is the correct procedure but I started looking for type instabilities in my functions and found this behaviour which I found odd enough to be worth asking here:

julia> using QuadGK

julia> fr(r::Real) = quadgk(h -> r* h^2, -1, 1)[1]
fr (generic function with 1 method)

julia> @code_warntype fr(2.)
Variables:
  #self# <optimized out>
  r::Float64
  #48::##48#49{Float64}

Body:
  begin 
      #48::##48#49{Float64} = $(Expr(:new, ##48#49{Float64}, :(r)))
      SSAValue(1) = $(Expr(:invoke, MethodInstance for #quadgk#15(::Array{Any,1}, ::Function, ::Function, ::Int64, ::Int64), :(QuadGK.#quadgk#15), :($(Expr(:foreigncall, :(:jl_alloc_array_1d), Array{Any,1}, svec(Any, Int64), Array{Any,1}, 0, 0, 0))), :(Main.quadgk), :(#48), -1, 1))
      return (Base.getfield)(SSAValue(1), 1)::Any
  end::Any

It seems to me that the quadgk()function is type-instable, because it the compiler sets its’ type to Any. Even if I set the result from quadgk to Float64 I still get a SSAValue(2) = (Base.getfield)(SSAValue(1), 1)::Any

Is this wanted behaviour? Am I missing something or doing something wrong?

Thanks!

Not sure, but Real is an abstract type, so you might want to:

function fr(r::T) where T <: Real

to set the type.

The argument declaration does not impact performance here. It only drives dispatch.

2 Likes

Ran into this problem, too. My best guess is the definition of Segment is the problem here:

struct Segment
    a::Number
    b::Number
    I
    E
end

(It doesn’t specialize for the various subtypes of Number.) There is an open bug report:
https://github.com/JuliaMath/QuadGK.jl/issues/15