#!/usr/bin/env node
'use strict';
const fs = require('fs');
const TIMINGS_DIR = 'build/__shard_timings__';
const OUT_PATH = 'build-weights.json';
function logDiff(fresh, previous) {
const deltas = [];
Object.keys(fresh).forEach(key => {
if (previous[key] !== undefined) {
deltas.push({key, delta: fresh[key] - previous[key]});
}
});
if (deltas.length === 0) {
return;
}
deltas.sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));
const absDeltas = deltas
.map(entry => Math.abs(entry.delta))
.sort((a, b) => a - b);
const mean =
absDeltas.reduce((sum, delta) => sum + delta, 0) / absDeltas.length;
const p95 = absDeltas[Math.floor(absDeltas.length * 0.95)];
console.log(
`Weight changes vs the previous run: mean |delta| = ${mean.toFixed(2)}s, ` +
`p95 = ${p95.toFixed(1)}s across ${deltas.length} bundles. ` +
'High variance here means shards should be determined from multiple runs.'
);
console.log('Largest changes:');
deltas.slice(0, 10).forEach(entry => {
console.log(
` ${entry.delta >= 0 ? '+' : ''}${entry.delta.toFixed(1)}s ${entry.key}`
);
});
}
function main() {
const fresh = {};
const files = fs
.readdirSync(TIMINGS_DIR)
.filter(name => name.endsWith('.json'));
files.forEach(name => {
const timings = JSON.parse(
fs.readFileSync(TIMINGS_DIR + '/' + name, 'utf8')
);
Object.keys(timings).forEach(key => {
fresh[key] = timings[key];
});
});
const freshKeys = Object.keys(fresh);
let previous = {};
try {
previous = JSON.parse(fs.readFileSync(OUT_PATH, 'utf8')).weights;
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
console.log('No previous weights found, skipping the diff.');
}
logDiff(fresh, previous);
fs.writeFileSync(
OUT_PATH,
JSON.stringify({version: 1, weights: fresh}, null, 2) + '\n'
);
console.log(`Wrote ${freshKeys.length} weights to ${OUT_PATH}.`);
}
try {
main();
} catch (error) {
console.log(
'Could not update build shard weights, keeping the previous ones.',
error
);
fs.rmSync(OUT_PATH, {force: true});
}