-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
I have noticed that the run-time of a function may significantly depend on whether the function body contains throw, even if no exception is thrown. The performance tips in the manual don't mention this. I therefore wonder whether it is a bug. The following MWE is adapted from the method typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T in abstractarray.jl.
@noinline throw_arg_err(msg) = throw(ArgumentError(msg))
function hv_cat(rows::Tuple{Vararg{Int}}, xs::Int...)
nr = length(rows)
nc = rows[1]
for i = 2:nr
if nc != rows[i]
throw(ArgumentError("mismatch")) # SLOW
# throw_arg_err("mismatch") # FAST
end
end
# Base.hvcat_fill(Matrix{Int}(undef, nr, nc), xs) # v1.6.1
Base.hvcat_fill!(Matrix{Int}(undef, nr, nc), xs) # master
end
The SLOW variant gives
julia> @btime hv_cat((1,1,1), 1,2,3);
107.800 ns (2 allocations: 144 bytes)
The FAST variant is 3x faster (and makes fewer allocations):
julia> @btime hv_cat((1,1,1), 1,2,3);
34.530 ns (1 allocation: 112 bytes)
Note that the code differs only in a branch that is not executed. I've tried to replace the call to Base.hvcat_fill! at the end with some other code, but then the difference disappeared. It also disappears if one changes the arguments to hv_cat((1,1), 1,2).
Julia Version 1.8.0-DEV.61
Commit 7553ca13cc (2021-06-21 17:18 UTC)
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: Intel(R) Core(TM) i3-10110U CPU @ 2.10GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-12.0.0 (ORCJIT, skylake)
The example also works for Julia 1.6.1 with the slight change indicated in the code.