-
-
Notifications
You must be signed in to change notification settings - Fork 5.7k
Description
We currently have a heuristic
Line 1227 in 6b934f9
| intptr_t nspec = (kwmt == NULL || kwmt == jl_type_type_mt || kwmt == jl_nonfunction_mt || kwmt == jl_kwcall_mt ? definition->nargs + 1 : jl_atomic_load_relaxed(&kwmt->max_args) + 2 + 2 * (mt == jl_kwcall_mt)); |
that decides how many specializations to generate for a varargs functions. It basically works as follows:
- If this is one method of some generic functions, look at all the other methods for the same generic function and specialize up to two more than the maximum number of arguments to any other method of this generic function.
- If not (e.g. it's some
(::Foo)(args...)method), specialize up to vararg length of two.
There are several problems with this scheme:
- It's somewhat ad-hoc and not always applicable. For example, we forcibly override the max_args for
invokehere:
Line 115 in 6b934f9
setfield!(typeof(invoke).name.mt, :max_args, 3, :monotonic) # invoke, f, T, args...
and for afoldl here:
Line 578 in 6b934f9
| setfield!(typeof(afoldl).name.mt, :max_args, 34, :monotonic) |
-
Our general direction has been towards a single unified method table, in which case the per-mt
max_argsheuristic doesn't work anymore. -
There's a bit of "spooky action at a distance" going on here where defining additional unrelated methods for a generic function can dramatically affect the performance of a different part of the code.
We should revisit this heuristic and see if we can come up with something that just look at the method itself (to start with, we could try just doing nargs+1 for everything and see what happens) or maybe derives some information from an abstract inference of the function. In addition, we should an escape hatch to the Method object itself that allows overriding the max_method heuristic for use in some of the cases mentioned above.