perf(compiler-cli): optimize cycle detection using a persistent cache #41271
Conversation
I am seeing noticeable improvements in several different projects with this change; cycle detection timings going from ~500ms to ~200ms. Since this runs on each incremental rebuild, that is a nice win (overall resolve phase time reduces from ~800ms to ~500ms) |
Super clever!
this.importGraph.addSyntheticImport(from, to); | ||
} | ||
} | ||
|
||
const NgCyclicResult = Symbol('NgCyclicResult'); | ||
type CyclicResultMarker = {}; |
Use a branded type to avoid open assignability.
For the compilation of a component, the compiler verifies that the imports it needs to generate to reference the used directives and pipes would not create an import cycle in the program. This requires visiting the transitive import graphs of all directive/pipe usage in search of the component file. The observation can be made that all directive/pipe usages can leverage the exploration work in search of the component file, thereby allowing sub-graphs of the import graph to be only visited once instead of repeatedly per usage. Additionally, the transitive imports of a file are no longer collected into a set to reduce memory pressure.
Nice.
What happens in an incremental build where a file (e.g. a.ts
) that was previously part of a cycle (e.g. a.ts
->b.ts
->a.ts
) is not changed but another file (e.g. b.ts
) is changed to break the cycle. Will the a.ts
SourceFile object still contain the sf[NgCyclicResult]
marker?
Answering my own question, I think, it seems that a new CycleResults
instance would be created that would have a new unique cyclic
object property. So even though a.ts
will contain an object in its sf[NgCyclicResult]
property, this object would not match the new one from the new CycleResults
instance. Right?
Indeed, that's why the unique markers are used. |
…#41271) For the compilation of a component, the compiler verifies that the imports it needs to generate to reference the used directives and pipes would not create an import cycle in the program. This requires visiting the transitive import graphs of all directive/pipe usage in search of the component file. The observation can be made that all directive/pipe usages can leverage the exploration work in search of the component file, thereby allowing sub-graphs of the import graph to be only visited once instead of repeatedly per usage. Additionally, the transitive imports of a file are no longer collected into a set to reduce memory pressure. PR Close #41271
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
For the compilation of a component, the compiler verifies that the
imports it needs to generate to reference the used directives and pipes
would not create an import cycle in the program. This requires visiting
the transitive import graphs of all directive/pipe usage in search of
the component file. The observation can be made that all directive/pipe
usages can leverage the exploration work in search of the component
file, thereby allowing sub-graphs of the import graph to be only visited
once instead of repeatedly per usage. Additionally, the transitive
imports of a file are no longer collected into a set to reduce memory
pressure.
The text was updated successfully, but these errors were encountered: