From fdc2f79855bcc5d48ec39cedd8558cf5494f895c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:11:19 +0900 Subject: [PATCH] chore(dev): tweak backend-memory-report --- .github/scripts/backend-memory-report.mjs | 87 ++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/.github/scripts/backend-memory-report.mjs b/.github/scripts/backend-memory-report.mjs index 0d2ba26cba..88a352f30c 100644 --- a/.github/scripts/backend-memory-report.mjs +++ b/.github/scripts/backend-memory-report.mjs @@ -37,6 +37,28 @@ const heapSnapshotCategories = [ 'Other non-JS objects', ]; +const heapSnapshotCategoriesColors = { + 'Total': 'gray', + 'Code': 'orange', + 'Strings': 'red', + 'JS arrays': 'cyan', + 'Typed arrays': 'green', + 'System objects': 'yellow', + 'Other JS objects': 'violet', + 'Other non-JS objects': 'pink', +}; + +const heapSnapshotCategoriesColorsHex = { + 'Total': '#888888', + 'Code': '#f28e2c', + 'Strings': '#e15759', + 'JS arrays': '#76b7b2', + 'Typed arrays': '#59a14f', + 'System objects': '#edc949', + 'Other JS objects': '#af7aa1', + 'Other non-JS objects': '#ff9da7', +}; + function formatNumber(value) { return numberFormatter.format(value); } @@ -265,6 +287,60 @@ function getHeapSnapshotCategoryValue(report, phase, category) { return Number.isFinite(value) ? value : null; } +function escapeCsvValue(value) { + return `"${String(value).replaceAll('"', '""')}"`; +} + +function renderHeapSnapshotSankey(report, phase, title) { + const total = getHeapSnapshotCategoryValue(report, phase, 'Total'); + if (total == null || total <= 0) return null; + + const categories = heapSnapshotCategories + .filter(category => category !== 'Total') + .map(category => { + const value = getHeapSnapshotCategoryValue(report, phase, category); + if (value == null || value <= 0) return null; + return { + category, + value, + }; + }) + .filter(value => value != null); + + if (categories.length === 0) return null; + + const nodeColors = { + [title]: heapSnapshotCategoriesColorsHex.Total, + }; + for (const { category } of categories) { + nodeColors[category] = heapSnapshotCategoriesColorsHex[category]; + } + + const lines = [ + `
${title} heap snapshot composition`, + '', + '```mermaid', + `%%{init: ${JSON.stringify({ + sankey: { + linkColor: 'target', + nodeAlignment: 'left', + nodeColors, + }, + })}}%%`, + 'sankey', + ]; + + for (const { category, value } of categories) { + lines.push(`${escapeCsvValue(title)},${escapeCsvValue(category)},${value}`); + } + + lines.push('```'); + lines.push(''); + lines.push('
'); + + return lines.join('\n'); +} + function formatHeapSnapshotCategoryLabel(category, baseValue, headValue, baseTotal, headTotal) { if (category === 'Total' || baseTotal == null || headTotal == null || baseTotal <= 0 || headTotal <= 0) return `**${category}**`; @@ -347,7 +423,7 @@ function renderHeapSnapshotTable(base, head, phase) { const deltaMedian = summary == null ? '-' : `${formatDeltaBytes(summary.median)}
${formatDeltaPercent(summary.median, baseValue)}`; const categoryLabel = formatHeapSnapshotCategoryLabel(category, baseValue, headValue, baseTotal, headTotal); - lines.push(`| ${categoryLabel} | ${formatBytes(baseValue)}
± ${baseSpread == null ? '-' : formatBytes(baseSpread)} | ${formatBytes(headValue)}
± ${headSpread == null ? '-' : formatBytes(headSpread)} | ${deltaMedian} | ${summary?.mad == null ? '-' : formatBytes(summary.mad)} | ${summary == null ? '-' : formatDeltaBytes(summary.min)} | ${summary == null ? '-' : formatDeltaBytes(summary.max)} |`); + lines.push(`| $\\color{${heapSnapshotCategoriesColors[category]}}{\\rule{8pt}{8pt}}$ ${categoryLabel} | ${formatBytes(baseValue)}
± ${baseSpread == null ? '-' : formatBytes(baseSpread)} | ${formatBytes(headValue)}
± ${headSpread == null ? '-' : formatBytes(headSpread)} | ${deltaMedian} | ${summary?.mad == null ? '-' : formatBytes(summary.mad)} | ${summary == null ? '-' : formatDeltaBytes(summary.min)} | ${summary == null ? '-' : formatDeltaBytes(summary.max)} |`); if (category === 'Total') { lines.push('| | | | | | | |'); } @@ -368,6 +444,15 @@ function renderHeapSnapshotSection(base, head) { '', ]; + for (const graph of [ + renderHeapSnapshotSankey(base, 'afterRequest', 'Base'), + renderHeapSnapshotSankey(head, 'afterRequest', 'Head'), + ]) { + if (graph == null) continue; + lines.push(graph); + lines.push(''); + } + return lines.join('\n'); }