perf(@angular/build): consolidate build worker pools with shared router - #33909
perf(@angular/build): consolidate build worker pools with shared router#33909alan-agius4 wants to merge 1 commit into
Conversation
ef02f83 to
0be1548
Compare
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request consolidates multiple worker pools into a single shared singleton worker pool that routes JavaScript transformation, Sass rendering, and i18n inlining tasks through a central router. While this consolidation improves resource management, a critical performance bug was identified in the i18n inliner worker: using WeakMaps keyed by Blob objects passed across the worker boundary results in a 0% cache hit rate, as structured cloning creates new Blob instances on every task, bypassing the cache entirely.
3223cd7 to
970c127
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces a shared build worker pool (getSharedBuildWorkerPool) and a central router (shared-worker-router.ts) to consolidate JS transformation, Sass rendering, and i18n inlining tasks into a single worker pool, optimizing resource usage. It also implements bounded in-memory caches in the i18n inliner worker to prevent unbounded memory growth. The review feedback suggests two improvement opportunities: utilizing the new partitionDiagnostics helper in i18n-inliner.ts to reduce duplication, and simplifying the string escaping logic in i18n-inliner-worker.ts for better readability.
Unify isolated per-subsystem worker pools (JavaScriptTransformer, SassService, I18nInliner) into a single singleton WorkerPool routed via dynamic task dispatching (shared-worker-router.ts). - Reduce active worker threads by 66.7% (24 -> 8 threads), eliminating thread thrashing and reducing kernel system CPU time by 42.3%. - Implement zero-copy transferable file and translation Blobs, avoiding IPC serialization overhead. - Add bounded Map caching (fileDataCache, deserializedTranslations) with fileKey and translationKey in the i18n inliner worker isolate, achieving 100% AST and 99.8% translation cache hit rates across locales without memory leaks. - Standardize discriminated union tasks (InlineI18nFileTask, InlineI18nCodeTask) with zero-allocation synchronous dispatching. | Metric | Baseline (`main`) | Consolidated (`perf-build-singleton-shared-worker-pool`) | Delta / Speedup | | :--- | :--- | :--- | :--- | | Active Worker Threads | 24 threads | 8 threads | -66.7% threads (-16 threads) | | Cold Build Duration (mean) | 1,182.0 ms | 1,180.5 ms | 1.00x faster (-0.1%) | | Cold Build Duration (min / max) | 1,151.7 ms / 1,228.2 ms | 1,156.8 ms / 1,224.2 ms | +5.1 ms / -4.0 ms | | P95 Build Latency | 1,228.2 ms | 1,224.2 ms | -0.3% (-4.0 ms) | | Throughput | 2,962.4 ops/sec | 2,966.1 ops/sec | +0.1% (+3.7 ops/sec) | | I18n Inlining Duration (Pure mean) | 696.0 ms | 217.9 ms | 3.19x faster (-68.7%) | | I18n Inlining (min / max) | 678.7 ms / 730.5 ms | 196.4 ms / 243.2 ms | 3.46x / 3.00x faster | | AST Cache Hit Rate (Subsequent Locales) | 0.0% (0 / 2,000) | 100.0% (2,000 / 2,000) | 100.0% cache hit rate | | Translation Cache Hit Rate | 0.0% (0 / 2,500) | 99.8% (2,495 / 2,500) | 99.8% cache hit rate | | Process RSS Delta | +2,786.0 MB | +1,519.7 MB | -45.5% (-1,266.3 MB saved) | | Final Process RSS | 2,842.1 MB | 1,576.4 MB | -44.5% (-1,265.7 MB saved) | | Kernel System CPU | 2,355.1 ms | 1,358.3 ms | -42.3% (1.73x less kernel CPU) | | Total CPU (User + Kernel) | 16,198.8 ms | 10,808.7 ms | -33.3% (1.50x CPU efficiency) | | Metric | Baseline (`main`) | Consolidated (`perf-build-singleton-shared-worker-pool`) | Delta / Speedup | | :--- | :--- | :--- | :--- | | Active Worker Threads | 24 threads | 8 threads | -66.7% threads (-16 threads) | | E2E Build Duration (mean) | 5,267.1 ms | 5,651.3 ms | +7.3% (+384.2 ms) | | E2E Build Duration (min / max) | 5,187.5 ms / 5,351.7 ms | 5,595.6 ms / 5,737.8 ms | +408.1 ms / +386.1 ms | | P95 Build Latency | 5,351.7 ms | 5,737.8 ms | +7.2% (+386.1 ms) | | Process RSS Delta | +2,215.3 MB | +2,124.3 MB | -4.1% (-91.0 MB saved) | | Final Process RSS | 2,296.2 MB | 2,204.7 MB | -4.0% (-91.5 MB saved) | | Kernel System CPU | 3,087.4 ms | 3,000.0 ms | -2.8% (1.03x less kernel CPU) | | Total CPU (User + Kernel) | 19,968.8 ms | 17,906.2 ms | -10.3% (-2,062.6 ms CPU saved) | > **Note on Concurrency Bounds**: On high-core machines, baseline's 24 unthrottled concurrent threads across 3 independent pools allow concurrent execution of different compiler phases, whereas the consolidated 8-thread singleton enforces strict concurrency bounds, trading ~380 ms wall-clock time for -2.06s lower total CPU work and lower peak memory. This is particularly important for lower-end machines and resource-constrained CI/container environments to avoid severe CPU starvation, thread thrashing, and out-of-memory crashes.
970c127 to
2cf891f
Compare
Unify isolated per-subsystem worker pools (JavaScriptTransformer, SassService, I18nInliner) into a single singleton WorkerPool routed via dynamic task dispatching (shared-worker-router.ts).
Benchmark 1: Subsystem Benchmark (500 Components, 500 SCSS Stylesheets, 5 Locales / 3,500 operations, 5 iterations)
main)perf-build-singleton-shared-worker-pool)Benchmark 2: End-to-End
ng buildApplication Benchmark (500 Components, 500 SCSS Stylesheets, 5 Locales, 5 iterations)main)perf-build-singleton-shared-worker-pool)