Skip to content

Parallelize CodeSplitter's not-exclusive CFA computation - #10396

Open
rhuanhianc wants to merge 1 commit into
gwtproject:mainfrom
rhuanhianc:perf/codesplitter-parallel-cfa
Open

Parallelize CodeSplitter's not-exclusive CFA computation#10396
rhuanhianc wants to merge 1 commit into
gwtproject:mainfrom
rhuanhianc:perf/codesplitter-parallel-cfa

Conversation

@rhuanhianc

Copy link
Copy Markdown

computeNotExclusiveCfaForFragments is quadratic in the number of exclusive fragments: for each fragment it traverses the run-asyncs of every other fragment. Applications with many split points pay heavily — with 231 split points this loop alone is 25.6% of the permutation's CPU, and CodeSplitter overall is 181s of an 11-minute compile.

The iterations are independent. ControlFlowAnalyzer's copy constructor deep-copies every mutable set, each traversal writes only to its own analyzer, and ControlFlowAnalyzer is purely analytical — it contains no setters on AST nodes. This runs them on a fixed thread pool.

Two constraints are respected:

  • Dependency-graph recording is stateful and order sensitive, so the parallel path is only taken when no recorder is installed. With -compileReport the original serial loop runs unchanged.
    -JProgram.getTypeArraylazily creates array types in a plain HashMap and is reachable from the traversal, so it is now synchronized. It is the only shared mutable state on this path; getAllArrayTypes, which already sorts to avoid nondeterminism, is not reachable from traverseFromRunAsync.

Happy to derive the pool size from -localWorkers instead of availableProcessors() if you'd prefer to avoid oversubscription when permutations are already compiled in parallel.

CodeSplitter drops from 38.4s to 17.0s with 122 split points and from 181.4s to 71.5s with 231. Generated JavaScript is byte-for-byte identical across 874 output files from four applications. ant -Dtarget=test dev passes: 1936 tests, 0 failures.

Fixes #10395

computeNotExclusiveCfaForFragments traverses the run-asyncs of every other
fragment for each fragment, so it is quadratic in fragment count. The
iterations are independent, so run them on a thread pool.

The serial loop is kept for when a dependency recorder is installed, since
recording is order sensitive. JProgram.getTypeArray is now synchronized, being
the only shared state the traversals create on demand.

CodeSplitter goes from 181.4s to 71.5s on an application with 231 split
points, with byte-identical output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CodeSplitter's not-exclusive CFA computation is quadratic in fragment count

1 participant