enhance(dev): improve mem report (#17118)

* wip

* wip

* Update report-backend-memory.yml

* Update report-backend-memory.yml

* Update .github/workflows/report-backend-memory.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
syuilo
2026-01-22 14:32:57 +09:00
committed by GitHub
parent f744b5711f
commit 2fa6ecc7ef
4 changed files with 99 additions and 40 deletions

View File

@@ -60,9 +60,9 @@ async function measureMemory() {
...process.env,
NODE_ENV: 'production',
MK_DISABLE_CLUSTERING: '1',
MK_FORCE_GC: '1',
},
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
execArgv: [...process.execArgv, '--expose-gc'],
});
let serverReady = false;
@@ -104,9 +104,21 @@ async function measureMemory() {
// Wait for memory to settle
await setTimeout(MEMORY_SETTLE_TIME);
// Get memory usage from the server process via /proc
const pid = serverProcess.pid;
const memoryInfo = await getMemoryUsage(pid);
const beforeGc = await getMemoryUsage(pid);
serverProcess.send('gc');
await new Promise((resolve) => {
serverProcess.once('message', (message) => {
if (message === 'gc ok') resolve();
});
});
await setTimeout(1000);
const afterGc = await getMemoryUsage(pid);
// Stop the server
serverProcess.kill('SIGTERM');
@@ -129,7 +141,8 @@ async function measureMemory() {
const result = {
timestamp: new Date().toISOString(),
memory: memoryInfo,
beforeGc,
afterGc,
};
return result;
@@ -144,19 +157,23 @@ async function main() {
}
// Calculate averages
const avgMemory = structuredClone(keys);
const beforeGc = structuredClone(keys);
const afterGc = structuredClone(keys);
for (const res of results) {
for (const key of Object.keys(avgMemory)) {
avgMemory[key] += res.memory[key];
for (const key of Object.keys(keys)) {
beforeGc[key] += res.beforeGc[key];
afterGc[key] += res.afterGc[key];
}
}
for (const key of Object.keys(avgMemory)) {
avgMemory[key] = Math.round(avgMemory[key] / SAMPLE_COUNT);
for (const key of Object.keys(keys)) {
beforeGc[key] = Math.round(beforeGc[key] / SAMPLE_COUNT);
afterGc[key] = Math.round(afterGc[key] / SAMPLE_COUNT);
}
const result = {
timestamp: new Date().toISOString(),
memory: avgMemory,
beforeGc,
afterGc,
};
// Output as JSON to stdout

View File

@@ -86,9 +86,17 @@ if (!envOption.disableClustering) {
ev.mount();
}
if (envOption.forceGc && global.gc != null) {
global.gc();
}
process.on('message', msg => {
if (msg === 'gc') {
if (global.gc != null) {
logger.info('Manual GC triggered');
global.gc();
if (process.send != null) process.send('gc ok');
} else {
logger.warn('Manual GC requested but gc is not available. Start the process with --expose-gc to enable this feature.');
}
}
});
readyRef.value = true;

View File

@@ -11,7 +11,6 @@ const envOption = {
verbose: false,
withLogTime: false,
quiet: false,
forceGc: false,
};
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {