Speeding Up Function with ::Function and ::Vararg input

Don’t give up so soon! :wink:

The following change makes funvar! just as fast again:

                args = let j = j
                    ntuple(i -> A[i][j], N)
                end
                σ[i] = f(Δx, args...)

in context:

function funvar!(σ::AbstractVector{<:Real},
                 x::Vector{Float64},
                 xl::Vector{Float64},
                 f::F,
                 A::Vararg{Vector{Float64},N}) where {F <: Function, N}
    L = length(xl)
    jstart = 1
    for i = 1:length(x)
        j = jstart
        while (j <= L) && abs(x[i] - xl[j]) > 0.1
            j += 1
        end
        if j <= L
            jstart = j
            while (j <= L) && abs(x[i] - xl[j]) < 0.1
                Δx = x[i] - xl[j]
                args = let j = j
                    ntuple(i -> A[i][j], N)
                end
                σ[i] = f(Δx, args...)
                j += 1
            end
        end
    end
end

The let j = j thing is necessary to avoid the weird performance issue with boxed variables in closures ( Performance Tips · The Julia Language)

Results:

julia> @btime funvar!($σ, $x, $xl, $test, $a, $b)
  890.985 μs (0 allocations: 0 bytes)

julia> @btime funvar!($σ, $x, $xl, $test, $a, $b, $c)
  938.801 μs (0 allocations: 0 bytes)

julia> @btime fun2!($σ, $x, $xl, $a, $b)
  851.805 μs (0 allocations: 0 bytes)

julia> @btime fun3!($σ, $x, $xl, $a, $b, $c)
  911.132 μs (0 allocations: 0 bytes)
2 Likes