Open arvidfm opened 4 days ago
Related Issues
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Note that this issue is related to #56718, but I figured that there was value in having an issue framed from a user's point of view, to show what the actual consequences of the issue is. (I also wanted somewhere to describe my findings.)
It may be the same as #65605, but that issue is less specific. Perhaps this issue can supersede it.
See also #50438, which this issue exacerbates.
Thank you for the detailed report. I suspect this is a manifestation of #56718.
Go version
go version go1.23.3 linux/amd64
Output of
go env
in your module/workspace:What did you do?
Compile the following code with
go build -a -gcflags 'play.ground/...=-d=ssa/trim/time'
:I also have a more complex MWE showing how e.g. embedding can exacerbate the issue.
What did you see happen?
All methods of
Foo[Bar, int]
(i.e.FooFunc
and its autogenerated wrapper methods) get instantiated/recompiled in bothbar
,baz
andmain
, even though they were already compiled inbar
, and neitherbaz
ormain
directly referenceFoo
, nor do they call methods that make use of the type:As a result of this, after the introduction of generics to our codebase, we are seeing build times up from a few seconds to over four minutes on clean builds or after changes to core code, with unit tests that previously took a few minutes sometimes taking up to an hour to compile and run. The way the generic types "infect" any packages that indirectly depend on them means that adding a single new method to a generic type results in an
O(nm)
build time increase forn
instantiations of the type andm
packages that indirectly depend on them, which can easily be roughly quadratic - even if the method is never actually called!In our case some methods are getting recompiled 40-50 times across as many packages for the same type parameters. As an example, for one method I count 28,790 invocations of
ssa.Compile
, but only 4,434 unique symbol names. (Note that these numbers also include associated autogenerated wrapper functions that seem to comprise about 90% of the symbols, inflated due to struct and interface embedding; there are only about 300-400 unique instantiations of the type that owns the methods.)If it's helpful, I've also collected profiling data from running the compiler on a few packages that are particularly slow to compile:
In general, it seems that we are hitting a pathological case, where a number of factors contribute to how many functions (and autogenerated wrappers) are generated for each instantiation, and thus how severely we are hit by this issue:
a.Add(b)
anda.Sub(b)
is nicer thanpkg.Add(a, b)
andpkg.Sub(a, b)
) - more methods means more duplicate compilationtype Bool[T any] Foo[T, bool]
- in lieu of proper generic type aliases, this will create a new interface type which results in another set of autogenerated wrappersWhat did you expect to see?
Foo[Bar, int]
to only be instantiated once, presumably in thebar
package: