Skip to content

Commit 155cdee

Browse files
committed
perf(webpack): add CI zip diagnostics
1 parent 645e2b5 commit 155cdee

2 files changed

Lines changed: 72 additions & 6 deletions

File tree

‎development/webpack/utils/plugins/ManifestPlugin/index.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,8 @@ export class ManifestPlugin<Z extends boolean> {
238238
development: true,
239239
});
240240
}
241+
242+
compressionController.finalize();
241243
}
242244

243245
/**

‎development/webpack/utils/plugins/ManifestPlugin/zip.ts‎

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ type CreateBrowserZipBuilderOptions = {
6666
type ZipCompressionController = {
6767
trackAsyncCompression: boolean;
6868
beginAsyncCompression: (assetSize: number) => () => void;
69+
finalize: () => void;
6970
recordSyncCompression: (assetSize: number, durationMs: number) => void;
7071
shouldUseAsyncCompression: (assetSize: number) => boolean;
7172
};
@@ -157,6 +158,7 @@ function createStaticZipCompressionController(
157158
return {
158159
trackAsyncCompression: false,
159160
beginAsyncCompression: () => () => undefined,
161+
finalize: () => undefined,
160162
recordSyncCompression: () => undefined,
161163
shouldUseAsyncCompression: (assetSize) => assetSize >= asyncSizeThreshold,
162164
};
@@ -177,15 +179,30 @@ function createAdaptiveZipCompressionController({
177179
maxAsyncJobs,
178180
memorySoftLimit,
179181
}: AdaptiveZipCompressionPolicy): ZipCompressionController {
182+
const shouldLogDiagnostics = IS_CI;
183+
const fallbackCounts = {
184+
belowThreshold: 0,
185+
maxAsyncBytes: 0,
186+
maxAsyncJobs: 0,
187+
memorySoftLimit: 0,
188+
};
180189
let asyncSizeThreshold = initialAsyncSizeThreshold;
181190
let inflightAsyncJobs = 0;
182191
let inflightAsyncBytes = 0;
183192
let syncSamples = 0;
184193
let asyncSamples = 0;
185194
let syncThroughput = 0;
186195
let asyncThroughput = 0;
196+
let retuneCount = 0;
187197
let lastRssSampleAt = -Infinity;
188198
let cachedRss = 0;
199+
let didLogSummary = false;
200+
201+
if (shouldLogDiagnostics) {
202+
console.log(
203+
`[zip-adaptive] start threshold_kib=${toKiB(asyncSizeThreshold)} max_async_jobs=${maxAsyncJobs} max_async_bytes=${maxAsyncBytes} memory_soft_limit=${memorySoftLimit}`,
204+
);
205+
}
189206

190207
function beginAsyncCompression(assetSize: number): () => void {
191208
inflightAsyncJobs += 1;
@@ -213,6 +230,17 @@ function createAdaptiveZipCompressionController({
213230
};
214231
}
215232

233+
function finalize(): void {
234+
if (!shouldLogDiagnostics || didLogSummary) {
235+
return;
236+
}
237+
238+
didLogSummary = true;
239+
console.log(
240+
`[zip-adaptive] summary final_threshold_kib=${toKiB(asyncSizeThreshold)} sync_samples=${syncSamples} async_samples=${asyncSamples} retunes=${retuneCount} below_threshold=${fallbackCounts.belowThreshold} max_jobs=${fallbackCounts.maxAsyncJobs} max_async_bytes=${fallbackCounts.maxAsyncBytes} memory_soft_limit_hits=${fallbackCounts.memorySoftLimit}`,
241+
);
242+
}
243+
216244
function recordSyncCompression(assetSize: number, durationMs: number): void {
217245
syncSamples += 1;
218246
syncThroughput = updateAverageThroughput(
@@ -226,12 +254,27 @@ function createAdaptiveZipCompressionController({
226254

227255
function shouldUseAsyncCompression(assetSize: number): boolean {
228256
const rss = getRss();
229-
return (
230-
assetSize >= asyncSizeThreshold &&
231-
inflightAsyncJobs < maxAsyncJobs &&
232-
inflightAsyncBytes + assetSize <= maxAsyncBytes &&
233-
rss + inflightAsyncBytes + assetSize <= memorySoftLimit
234-
);
257+
if (assetSize < asyncSizeThreshold) {
258+
fallbackCounts.belowThreshold += 1;
259+
return false;
260+
}
261+
262+
if (inflightAsyncJobs >= maxAsyncJobs) {
263+
fallbackCounts.maxAsyncJobs += 1;
264+
return false;
265+
}
266+
267+
if (inflightAsyncBytes + assetSize > maxAsyncBytes) {
268+
fallbackCounts.maxAsyncBytes += 1;
269+
return false;
270+
}
271+
272+
if (rss + inflightAsyncBytes + assetSize > memorySoftLimit) {
273+
fallbackCounts.memorySoftLimit += 1;
274+
return false;
275+
}
276+
277+
return true;
235278
}
236279

237280
function retuneAsyncThreshold(): void {
@@ -245,17 +288,33 @@ function createAdaptiveZipCompressionController({
245288
inflightAsyncJobs >= maxAsyncJobs ||
246289
inflightAsyncBytes >= maxAsyncBytes * 0.75 ||
247290
getRss() >= memorySoftLimit;
291+
const previousAsyncSizeThreshold = asyncSizeThreshold;
292+
let retuneReason: 'async_better' | 'sync_better' | 'under_pressure' | null =
293+
null;
248294

249295
if (syncIsClearlyBetter || underPressure) {
250296
asyncSizeThreshold = Math.min(
251297
MAX_ASYNC_COMPRESSION_SIZE,
252298
Math.floor(asyncSizeThreshold * 1.5),
253299
);
300+
retuneReason = underPressure ? 'under_pressure' : 'sync_better';
254301
} else if (asyncIsClearlyBetter) {
255302
asyncSizeThreshold = Math.max(
256303
MIN_ASYNC_COMPRESSION_SIZE,
257304
Math.floor(asyncSizeThreshold / 1.25),
258305
);
306+
retuneReason = 'async_better';
307+
}
308+
309+
if (
310+
shouldLogDiagnostics &&
311+
retuneReason &&
312+
asyncSizeThreshold !== previousAsyncSizeThreshold
313+
) {
314+
retuneCount += 1;
315+
console.log(
316+
`[zip-adaptive] retune from_kib=${toKiB(previousAsyncSizeThreshold)} to_kib=${toKiB(asyncSizeThreshold)} reason=${retuneReason} sync_throughput=${Math.round(syncThroughput)} async_throughput=${Math.round(asyncThroughput)} inflight_jobs=${inflightAsyncJobs} inflight_async_bytes=${inflightAsyncBytes}`,
317+
);
259318
}
260319
}
261320

@@ -272,6 +331,7 @@ function createAdaptiveZipCompressionController({
272331
return {
273332
trackAsyncCompression: true,
274333
beginAsyncCompression,
334+
finalize,
275335
recordSyncCompression,
276336
shouldUseAsyncCompression,
277337
};
@@ -473,3 +533,7 @@ function updateAverageThroughput(
473533
: currentAverage * (1 - THROUGHPUT_SMOOTHING_FACTOR) +
474534
throughput * THROUGHPUT_SMOOTHING_FACTOR;
475535
}
536+
537+
function toKiB(bytes: number): number {
538+
return Math.round(bytes / KiB);
539+
}

0 commit comments

Comments
 (0)