-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Function over-specialization on unused parts of types #26834
Comments
Yes, it would be great to allow
Even better to handle it automatically of course, but that's going to be a taller order. |
Is it really true that compilation time can be saved?
|
In a
There are lots of "quick" functions which aren't get inlined aren't called often. For example, checking convergence after iterations and updating progress bars. |
Ah, you got the order of your fields wrong, that's why I was confused. What you are asking for is basically rudimentary inheritance:
Now, anything that takes a |
Run into the exact same issue when trying to use "finite field algebra + Chinese remainder theorem" to achieve arbitrary precision computation of fibonacci numbers.
MWEusing Mods, Primes
# computing fib function by powering the matrix
function fib(::Type{T}, n::Int) where T
(T[0 1; 1 1] ^ (n-1) * [1, 1])[2]
end
function big_integer_solve(f, ::Type{TI}, max_iter::Int=100) where TI
N = typemax(TI)
local res, respre, YS
for k = 1:max_iter
N = prevprime(N-TI(1))
T = Mods.Mod{N,TI}
rk = f(T)
if k != 1
push!(YS, rk)
res = Mods.CRT(YS...)
respre == res && return res # converged
respre = res
else # k=1
YS = Any[]
push!(YS, rk)
respre = BigInt(value(rk))
end
end
@warn "result is potentially inconsistent."
return res
end
big_integer_solve(T->fib(T, 1000), Int32) I guess there is no easy solution for this issue yet? I wish the type parameter (or the modulus) of |
xref #11339 |
This is best explained by an example.
In this setup, both
other_stuff!
andstepper!
will specialize on every type parameter change{F,T}
. However, let's say thatF
changes often andT
doesn't change often. Then both functions will recompile every time when onlystepper!
needs to. Thus compilation time is increased.A user can work around it by pulling apart the pieces of the type they need:
here
other_stuff2
only takes in a value which has typeT
, so ifT
is unchanged then the same compiled code can be re-used (if it doesn't inline and all of that). However, as the operations inother_stuff!
get more complicated, the complexity of the function signature and the return that are required to make this work grows.I see this as a common pattern in scientific computing libraries like DiffEq, Optim, etc. since the code for the general algorithms is much larger in comparison to the code that actually has to touch function calls. The larger algorithm has convergence checks, output generation, etc. that are usually always the same (since there
T
would just beFloat64
which most users would be using). However, the entire function stacks are recompiling each time due to the over-specialization on unused parts of types in theother_stuff!
functions. From tests it seems thatF
specialization can be a big deal for many use cases (as much as 2x-4x in comparison to FunctionWrappers.jl in some real cases!) so that cannot be easily dropped, but fully decomposing every "non-f function" is quite laborious.The nice option would be for the compiler to recognize this is the case and just not specialize on these functions. Another option would be to allow
@nospecialize
on type parameters.The text was updated successfully, but these errors were encountered: