From 96185d00d19b79becfb49b8990c927f1a2784cb1 Mon Sep 17 00:00:00 2001 From: Agnieszka Gawrys Date: Mon, 6 Nov 2023 16:20:47 -0800 Subject: [PATCH] Add parcel query option to view de/serialization times & graph size (#9361) * add parcel query option to view serialization times * flow * make serialize wrapper * format name col --- packages/dev/query/src/cli.js | 63 ++++++++++++++++++++++++++++++--- packages/dev/query/src/index.js | 52 ++++++++++++++++++++------- 2 files changed, 99 insertions(+), 16 deletions(-) diff --git a/packages/dev/query/src/cli.js b/packages/dev/query/src/cli.js index 32665480f09..ad86308082a 100644 --- a/packages/dev/query/src/cli.js +++ b/packages/dev/query/src/cli.js @@ -10,6 +10,7 @@ import repl from 'repl'; import os from 'os'; import nullthrows from 'nullthrows'; import invariant from 'assert'; +import {serialize} from 'v8'; // $FlowFixMe import {table} from 'table'; @@ -37,9 +38,8 @@ export async function run(input: string[]) { } console.log('Loading graphs...'); - let {assetGraph, bundleGraph, bundleInfo, requestTracker} = await loadGraphs( - cacheDir, - ); + let {assetGraph, bundleGraph, bundleInfo, requestTracker, cacheInfo} = + await loadGraphs(cacheDir); if (requestTracker == null) { console.error('Request Graph could not be found'); @@ -591,7 +591,54 @@ export async function run(input: string[]) { return entryBundleGroup; } + // eslint-disable-next-line no-unused-vars + function inspectCache(_) { + // displays sizing of various entries of the cache + let table: Array> = []; + table.push([ + 'Graphs', + 'Size (bytes)', + 'Deserialize (ms)', + 'Serialize (ms)', + ]); + let serialized: Map = new Map(); + serialized.set('RequestGraph', timeSerialize(requestTracker)); + serialized.set('bundle_graph_request', timeSerialize(bundleGraph)); + serialized.set('asset_graph_request', timeSerialize(assetGraph)); + for (let [k, v] of nullthrows(cacheInfo).entries()) { + let s = serialized.get(k); + invariant(s != null); + let name = k.includes('_request') ? k.split('_request')[0] : k; + table.push([name, ...v, s]); + } + function getColumnSum(t: Array>, col: number) { + if (t == null) { + return ''; + } + const initialValue = 0; + let column = t.map(r => r[col]); + column.shift(); + invariant(column != null); + return column.reduce( + (accumulator, currentValue) => accumulator + currentValue, + initialValue, + ); + } + table.push([ + 'Totals', + getColumnSum(table, 1), + getColumnSum(table, 2), + getColumnSum(table, 3), + ]); + _printStatsTable('Cache Info', table); + } + function timeSerialize(graph) { + let date = Date.now(); + serialize(graph); + date = Date.now() - date; + return date; + } function _printStatsTable(header, data) { const config = { columnDefault: { @@ -738,7 +785,8 @@ export async function run(input: string[]) { server.context.assetGraph = assetGraph; // $FlowFixMe[prop-missing] server.context.requestTracker = requestTracker; - + // $FlowFixMe[prop-missing] + server.context.cacheInfo = cacheInfo; for (let [name, cmd] of new Map([ [ 'getAsset', @@ -887,6 +935,13 @@ export async function run(input: string[]) { action: findAsset, }, ], + [ + 'inspectCache', + { + help: 'Cache Information', + action: inspectCache, + }, + ], [ 'findAssetWithSymbol', { diff --git a/packages/dev/query/src/index.js b/packages/dev/query/src/index.js index 1746fd010db..2875c909bce 100644 --- a/packages/dev/query/src/index.js +++ b/packages/dev/query/src/index.js @@ -25,6 +25,7 @@ export async function loadGraphs(cacheDir: string): Promise<{| bundleGraph: ?BundleGraph, requestTracker: ?RequestTracker, bundleInfo: ?Map, + cacheInfo: ?Map>, |}> { function filesBySizeAndModifiedTime() { let files = fs.readdirSync(cacheDir).map(f => { @@ -38,21 +39,32 @@ export async function loadGraphs(cacheDir: string): Promise<{| return files.map(([f]) => f); } + let cacheInfo: Map> = new Map(); + let timeToDeserialize = 0; + let requestTracker; const cache = new LMDBCache(cacheDir); for (let f of filesBySizeAndModifiedTime()) { // Empty filename or not the first chunk if (path.extname(f) !== '' && !f.endsWith('-0')) continue; try { - let obj = v8.deserialize( - await cache.getLargeBlob(path.basename(f).slice(0, -'-0'.length)), + let file = await cache.getLargeBlob( + path.basename(f).slice(0, -'-0'.length), ); + + cacheInfo.set('RequestGraph', [Buffer.byteLength(file)]); + + timeToDeserialize = Date.now(); + let obj = v8.deserialize(file); + timeToDeserialize = Date.now() - timeToDeserialize; + /* if (obj.assetGraph != null && obj.assetGraph.value.hash != null) { assetGraph = AssetGraph.deserialize(obj.assetGraph.value); } else if (obj.bundleGraph != null) { bundleGraph = BundleGraph.deserialize(obj.bundleGraph.value); } else */ if (obj['$$type']?.endsWith('RequestGraph')) { + let date = Date.now(); requestTracker = new RequestTracker({ graph: RequestGraph.deserialize(obj.value), // $FlowFixMe @@ -60,6 +72,7 @@ export async function loadGraphs(cacheDir: string): Promise<{| // $FlowFixMe options: null, }); + timeToDeserialize += Date.now() - date; break; } } catch (e) { @@ -75,7 +88,8 @@ export async function loadGraphs(cacheDir: string): Promise<{| // Load graphs by finding the main subrequests and loading their results let assetGraph, bundleGraph, bundleInfo; - + cacheInfo.set('bundle_graph_request', []); + cacheInfo.set('asset_graph_request', []); invariant(requestTracker); let buildRequestId = requestTracker.graph.getNodeIdByContentKey( 'parcel_build_request', @@ -94,8 +108,13 @@ export async function loadGraphs(cacheDir: string): Promise<{| ); if (bundleGraphRequestNode != null) { bundleGraph = BundleGraph.deserialize( - (await loadLargeBlobRequestRequest(cache, bundleGraphRequestNode)) - .bundleGraph.value, + ( + await loadLargeBlobRequestRequest( + cache, + bundleGraphRequestNode, + cacheInfo, + ) + ).bundleGraph.value, ); let assetGraphRequest = getSubRequests( @@ -103,12 +122,12 @@ export async function loadGraphs(cacheDir: string): Promise<{| ).find(n => n.type === 'request' && n.value.type === 'asset_graph_request'); if (assetGraphRequest != null) { assetGraph = AssetGraph.deserialize( - (await loadLargeBlobRequestRequest(cache, assetGraphRequest)).assetGraph - .value, + (await loadLargeBlobRequestRequest(cache, assetGraphRequest, cacheInfo)) + .assetGraph.value, ); } } - + cacheInfo.get('RequestGraph')?.push(timeToDeserialize); let writeBundlesRequest = buildRequestSubRequests.find( n => n.type === 'request' && n.value.type === 'write_bundles_request', ); @@ -121,12 +140,21 @@ export async function loadGraphs(cacheDir: string): Promise<{| >); } - return {assetGraph, bundleGraph, requestTracker, bundleInfo}; + return {assetGraph, bundleGraph, requestTracker, bundleInfo, cacheInfo}; } -async function loadLargeBlobRequestRequest(cache, node) { +async function loadLargeBlobRequestRequest(cache, node, cacheInfo) { invariant(node.type === 'request'); - return v8.deserialize( - await cache.getLargeBlob(nullthrows(node.value.resultCacheKey)), + + let cachedFile = await cache.getLargeBlob( + nullthrows(node.value.resultCacheKey), ); + cacheInfo.get(node.value.type)?.push(cachedFile.byteLength); //Add size + + let TTD = Date.now(); + let result = v8.deserialize(cachedFile); + TTD = Date.now() - TTD; + cacheInfo.get(node.value.type)?.push(TTD); + + return result; }