|
| 1 | +/* eslint-disable no-console -- expected to log */ |
| 2 | + |
| 3 | +/* eslint-disable-next-line n/no-unsupported-features/node-builtins -- developer script */ |
| 4 | +import { styleText } from "node:util"; |
| 5 | +import babar from "babar"; |
| 6 | +import Table from "cli-table"; |
| 7 | +import { CLI } from "../dist/es/index.js"; |
| 8 | + |
| 9 | +async function iteration() { |
| 10 | + if (global.gc) { |
| 11 | + global.gc(); |
| 12 | + } |
| 13 | + |
| 14 | + const cli = new CLI(); |
| 15 | + const htmlValidate = await cli.getValidator(); |
| 16 | + await htmlValidate.validateString("<!DOCTYPE html><html><head></head><body></body></html>"); |
| 17 | +} |
| 18 | + |
| 19 | +function prettySize(value) { |
| 20 | + if (value > 1024 * 1024) { |
| 21 | + return `${(value / 1024 / 1024).toFixed(1)}mb`; |
| 22 | + } else if (value > 1024) { |
| 23 | + return `${Math.round((value / 1024) * 10) / 10}kb`; |
| 24 | + } else { |
| 25 | + return `${value}`; |
| 26 | + } |
| 27 | +} |
| 28 | + |
| 29 | +function percent(cur, prev) { |
| 30 | + const k = cur / prev; |
| 31 | + const p = (k - 1) * 1000; |
| 32 | + return p > 0 ? Math.floor(p) / 10 : Math.ceil(p) / 10; |
| 33 | +} |
| 34 | + |
| 35 | +if (global.gc) { |
| 36 | + console.log(styleText("red", "⚠ Running with garbage collection")); |
| 37 | + console.log(styleText("red", " Remove --expose-gc from node options to run without")); |
| 38 | +} else { |
| 39 | + console.log(styleText("green", "✓ Running without garbage collection")); |
| 40 | +} |
| 41 | + |
| 42 | +const numCycles = process.argv.length > 2 ? Number(process.argv[2]) : 25000; |
| 43 | +const bucketSize = Math.floor(numCycles / 10); |
| 44 | +const journal = []; |
| 45 | +for (let cycle = 0; cycle <= numCycles; cycle++) { |
| 46 | + await iteration(); |
| 47 | + const { heapTotal, heapUsed } = process.memoryUsage(); |
| 48 | + if (cycle % bucketSize === 0) { |
| 49 | + const previousTotal = journal.length > 0 ? journal[journal.length - 1].heapTotal : heapTotal; |
| 50 | + const previousUsed = journal.length > 0 ? journal[journal.length - 1].heapUsed : heapUsed; |
| 51 | + journal.push({ |
| 52 | + cycle, |
| 53 | + heapUsed, |
| 54 | + heapTotal, |
| 55 | + "heapTotal (mb)": `${(heapTotal / 1024 ** 2).toFixed(1)}mb`, |
| 56 | + "heapTotal (%)": `${percent(heapTotal, previousTotal)}%`, |
| 57 | + "heapUsed (mb)": `${(heapUsed / 1024 ** 2).toFixed(1)}mb`, |
| 58 | + "heapUsed (%)": `${percent(heapUsed, previousUsed)}%`, |
| 59 | + }); |
| 60 | + } |
| 61 | + process.stdout.clearLine(0); |
| 62 | + process.stdout.cursorTo(0); |
| 63 | + process.stdout.write( |
| 64 | + `${cycle} / ${numCycles} iterations done, ${prettySize(heapUsed)} heap used, ${prettySize(heapTotal)} heap total`, |
| 65 | + ); |
| 66 | +} |
| 67 | +process.stdout.write("\n"); |
| 68 | +const table = new Table({ |
| 69 | + head: ["Bucket", "Used (mb)", "Used (%)", "Total (mb)", "Total (%)"], |
| 70 | + colAligns: ["right", "right", "right", "right", "right"], |
| 71 | + style: { head: ["cyan"], compact: true }, |
| 72 | +}); |
| 73 | +table.push( |
| 74 | + ...journal.map((it, index) => { |
| 75 | + return [ |
| 76 | + index, |
| 77 | + it["heapUsed (mb)"], |
| 78 | + it["heapUsed (%)"], |
| 79 | + it["heapTotal (mb)"], |
| 80 | + it["heapTotal (%)"], |
| 81 | + ]; |
| 82 | + }), |
| 83 | +); |
| 84 | +console.log("Heap profile"); |
| 85 | +console.log(table.toString()); |
| 86 | + |
| 87 | +const values = journal.map((it) => it.heapTotal); |
| 88 | +console.log( |
| 89 | + "min:", |
| 90 | + (Math.min(...values) / 1024 ** 2).toFixed(1), |
| 91 | + "max:", |
| 92 | + (Math.max(...values) / 1024 ** 2).toFixed(1), |
| 93 | +); |
| 94 | + |
| 95 | +const heapTotal = journal.map((it, i) => [i, it.heapTotal / 1024 ** 2]); |
| 96 | +const chartTotal = babar(heapTotal, { |
| 97 | + caption: "Heap total (MB per 100 runs)", |
| 98 | + color: "green", |
| 99 | + width: 60, |
| 100 | + height: 20, |
| 101 | + minY: 0, |
| 102 | + yFractions: 0, |
| 103 | +}); |
| 104 | +console.log(chartTotal); |
| 105 | + |
| 106 | +const heapUsed = journal.map((it, i) => [i, it.heapUsed / 1024 ** 2]); |
| 107 | +const chartUsed = babar(heapUsed, { |
| 108 | + caption: "Heap used (MB per 100 runs)", |
| 109 | + color: "green", |
| 110 | + width: 60, |
| 111 | + height: 20, |
| 112 | + minY: 0, |
| 113 | + yFractions: 0, |
| 114 | +}); |
| 115 | +console.log(chartUsed); |
0 commit comments