EDIT: s/specialize/instantiate/g
We have some code which defines a large generic type (a parser), which is instantiated in different ways to generate different kinds of output.
The crate dependency structure is (where a <- b
is "b depends on a"):
parser <- instantiation1 <- usercrate
^------ instantiation2 <--/
^------ instantiation3 <--/
^------ ... <--/
That is, there's a fan-out in the middle of the dependency graph.
Each instantiation crate is basically:
use parser::Parser;
use something::{Something, Else};
type SomethingParser<'a> = Parser<'a, Something, Else>;
I.e. it just defines a type alias for the specialization.
usercrate
brings this all together, and makes use of all the instantiations.
The problem is that usercrate
has a long build time, and a significant amount of that is from the instantiations, which have been deferred to their use-sites.
If we modify the instantiationN
crates to make a dummy invocation of the parser (via public, but unused, function which invokes the parser on dummy input), then it moves the instantiation into the instantiationN
crates. This still takes CPU time, but it parallelizes well and the overall wallclock time is reduced. In particular, the wallclock time for usercrate
goes down significantly.
We're using codegen-units, of course, but this shows that it is not enough to compensate for completely independent rustc invocations. Perhaps more intelligent scheduling of work within rustc could help improve this.
This also suggests that if there were multiple usercrateN
s then doing it eagerly would do it once, but lazily would defer the work to be done independently in each user crate.
I'm also not sure if this a specific side-effect of using type
ie, just a type alias, which doesn't really do anything. Would using a newtype wrapper help? But that would be awkward because it would also need impls for a lot of forwarding methods.
But alternatively, I was wondering if it would be worth adding an attribute to (something) to indicate that eager instantiation would be useful. I'm not sure what it would be added to; I guess either:
- a generic type definition
- a specific instantiation (like
type
above)
There's also the question of whether this only applies to full instantiations, or where there's some benefit to eagerly partially instantiating. In that case it might also make sense to annotate specific type parameters as being good for instantiation.
I'm thinking of this as a pure hint, along the lines of #[inline]
, where there's no semantic change, and the compiler is free to ignore it.
Thoughts? Has anyone run into this before?