There are places in Base where manually outlining error throwing can give significant (relative) speedups. For example, changing https://github.com/JuliaLang/julia/blob/bdd0e99d50dd358180965a7de5176bca83727417/base/parse.jl#L7-L15 to:
function parse2(::Type{T}, c::Char, base::Integer=36) where T<:Integer
a::Int = (base <= 36 ? 10 : 36)
2 <= base <= 62 || throw_invalid_base(base)
d = '0' <= c <= '9' ? c-'0' :
'A' <= c <= 'Z' ? c-'A'+10 :
'a' <= c <= 'z' ? c-'a'+a : throw_invalid_digit(c)
d < base || throw_invalid_base_digit(base, c)
convert(T, d)
end
@noinline throw_invalid_base(base) = throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
@noinline throw_invalid_digit(c) = throw(ArgumentError("invalid digit: $(repr(c))"))
@noinline throw_invalid_base_digit(base, c) = throw(ArgumentError("invalid base $base digit $(repr(c))"))
has a measurable impact:
julia> @btime parse2(Int64, 'a', 36);
3.864 ns (0 allocations: 0 bytes)
julia> @btime parse(Int64, 'a', 36);
5.422 ns (0 allocations: 0 bytes)
Is it worth to go through these type of functions and manually outline the error throwing, or is the plan to deal with all of that in another way which does not require manually moving them out?
is the plan to deal with all of that in another way which does not require manually moving them out?
Yes.
Ref. potentially related https://github.com/JuliaLang/julia/pull/22210#issuecomment-312504510 and https://github.com/JuliaLang/julia/pull/22210#discussion_r125795539. Best!
Most helpful comment
Yes.