Skip to content

Commit

Permalink
feat: stat-bundle and stat-plan scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
turadg committed Jun 17, 2024
1 parent a0115ed commit bd0edcb
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 0 deletions.
1 change: 1 addition & 0 deletions packages/agoric-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"@endo/nat": "^5.0.7",
"@endo/patterns": "^1.4.0",
"@endo/promise-kit": "^1.1.2",
"@endo/zip": "^1.0.5",
"@iarna/toml": "^2.2.3",
"anylogger": "^0.21.0",
"chalk": "^5.2.0",
Expand Down
9 changes: 9 additions & 0 deletions packages/agoric-cli/scripts/stat-bundle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env node
import assert from 'node:assert';
import process from 'node:process';
import { statBundle } from '../src/lib/bundles.js';

const filename = process.argv[2];
assert(filename, 'usage: stat-bundle.js <filename>');

await statBundle(filename);
5 changes: 5 additions & 0 deletions packages/agoric-cli/scripts/stat-plans.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node
import process from 'node:process';
import { statPlans } from '../src/lib/bundles.js';

await statPlans(process.cwd());
98 changes: 98 additions & 0 deletions packages/agoric-cli/src/lib/bundles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// @ts-check

/* global Buffer */

import assert from 'node:assert/strict';
import fs from 'node:fs';
import { join } from 'node:path';

import { ZipReader } from '@endo/zip';

/** @import {Bundle} from '@agoric/swingset-vat'; */
/** @import {CoreEvalPlan} from '@agoric/deploy-script-support/src/writeCoreEvalParts.js' */

const PACKAGE_NAME_RE = /(?<packageName>.*-v[\d.]+)\//;

/**
* @typedef {{ name: string, label: string, location: string, modules: Record<string, {compartment: string, module: string}>}} Compartment
*/

/**
* @typedef CompartmentMap
* @property {string[]} tags
* @property {{compartment: string, module: string}} entry
* @property {Record<string, Compartment>} compartments
*/

/** @param {Bundle} bundleObj*/
export const extractBundleInfo = async bundleObj => {
if (bundleObj.moduleFormat !== 'endoZipBase64') {
throw new Error('only endoZipBase64 is supported');
}

const contents = Buffer.from(bundleObj.endoZipBase64, 'base64');

const zipReader = new ZipReader(contents);
const { files } = zipReader;

const cmapEntry = files.get('compartment-map.json');
/** @type {CompartmentMap} */
const compartmentMap = JSON.parse(Buffer.from(cmapEntry.content).toString());

// XXX mapIter better but requires SES
const fileSizes = Object.fromEntries(
Array.from(files.values()).map(f => [
f.name,
// bundle contents are not compressed
f.content.length,
]),
);

return { compartmentMap, fileSizes };
};

// UNTIL https://github.com/endojs/endo/issues/1656
/** @param {string} bundleFilename */
export const statBundle = async bundleFilename => {
const bundle = fs.readFileSync(bundleFilename, 'utf8');
/** @type {Bundle} */
const bundleObj = JSON.parse(bundle);
console.log('\nBUNDLE', bundleObj.moduleFormat, bundleFilename);

const info = await extractBundleInfo(bundleObj);
assert(info, 'no bundle info');

/** @type {Record<string, number>} */
const byPackage = {};
let totalSize = 0;
for (const [filename, size] of Object.entries(info.fileSizes)) {
totalSize += size;
if (filename === 'compartment-map.json') {
continue;
}
const { packageName } = filename.match(PACKAGE_NAME_RE)?.groups ?? {};
assert(packageName, `invalid filename ${filename}`);
byPackage[packageName] ||= 0;
byPackage[packageName] += size;
}

console.log('Sum of file sizes in each package:');
console.table(byPackage);

console.log('total size:', totalSize);
};

/** @param {string} path */
export const statPlans = async path => {
const files = await fs.promises.readdir(path);
const planfiles = files.filter(f => f.endsWith('plan.json'));

for (const planfile of planfiles) {
/** @type {CoreEvalPlan} */
const plan = JSON.parse(fs.readFileSync(join(path, planfile), 'utf8'));
console.log('\n**\nPLAN', plan.name);
for (const bundle of plan.bundles) {
await statBundle(bundle.fileName);
}
}
};

0 comments on commit bd0edcb

Please sign in to comment.