diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2026-01-22 18:53:53 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-22 18:53:53 +0900 |
| commit | a168e7b6486013d05ba836d9a1d084a7708c19fb (patch) | |
| tree | a9f0a1803e2b32c5c17e0d693777f98c90a8b1b8 | |
| parent | Update report-backend-memory.yml (diff) | |
| download | misskey-a168e7b6486013d05ba836d9a1d084a7708c19fb.tar.gz misskey-a168e7b6486013d05ba836d9a1d084a7708c19fb.tar.bz2 misskey-a168e7b6486013d05ba836d9a1d084a7708c19fb.zip | |
enhance(dev): Improve mem report (#17119)
* wip
* Update report-backend-memory.yml
* Update report-backend-memory.yml
* Update measure-memory.mjs
* Update report-backend-memory.yml
| -rw-r--r-- | .github/workflows/report-backend-memory.yml | 33 | ||||
| -rw-r--r-- | packages/backend/scripts/measure-memory.mjs | 58 |
2 files changed, 78 insertions, 13 deletions
diff --git a/.github/workflows/report-backend-memory.yml b/.github/workflows/report-backend-memory.yml index 30918f44db..bf2e311c83 100644 --- a/.github/workflows/report-backend-memory.yml +++ b/.github/workflows/report-backend-memory.yml @@ -85,7 +85,8 @@ jobs: --argjson VmRSS "$(calc $1 VmRSS)" \ --argjson VmHWM "$(calc $1 VmHWM)" \ --argjson VmSize "$(calc $1 VmSize)" \ - '{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize}') + --argjson VmData "$(calc $1 VmData)" \ + '{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize, VmData: $VmData}') echo "$JSON" } @@ -93,7 +94,8 @@ jobs: JSON=$(jq -c -n \ --argjson beforeGc "$(variation beforeGc)" \ --argjson afterGc "$(variation afterGc)" \ - '{beforeGc: $beforeGc, afterGc: $afterGc}') + --argjson afterRequest "$(variation afterRequest)" \ + '{beforeGc: $beforeGc, afterGc: $afterGc, afterRequest: $afterRequest}') echo "res=$JSON" >> "$GITHUB_OUTPUT" - id: build-comment @@ -108,20 +110,37 @@ jobs: echo >> ./output.md table() { + echo "| Metric | base (MB) | head (MB) | Diff (MB) | Diff (%) |" >> ./output.md + echo "|--------|------:|------:|------:|------:|" >> ./output.md + line() { + METRIC=$2 BASE=$(echo "$RES" | jq -r ".${1}.${2}.base") HEAD=$(echo "$RES" | jq -r ".${1}.${2}.head") DIFF=$(echo "$RES" | jq -r ".${1}.${2}.diff") DIFF_PERCENT=$(echo "$RES" | jq -r ".${1}.${2}.diff_percent") - echo "| ${2} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB (${DIFF_PERCENT}%) |" >> ./output.md + if (( $(echo "$DIFF_PERCENT > 0" | bc -l) )); then + DIFF="+$DIFF" + DIFF_PERCENT="+$DIFF_PERCENT" + fi + + # highlight VmRSS + if [ "$2" = "VmRSS" ]; then + METRIC="**${METRIC}**" + BASE="**${BASE}**" + HEAD="**${HEAD}**" + DIFF="**${DIFF}**" + DIFF_PERCENT="**${DIFF_PERCENT}**" + fi + + echo "| ${METRIC} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB | ${DIFF_PERCENT}% |" >> ./output.md } - echo "| Metric | base | head | Diff |" >> ./output.md - echo "|--------|------|------|------|" >> ./output.md line $1 VmRSS line $1 VmHWM line $1 VmSize + line $1 VmData } echo "### Before GC" >> ./output.md @@ -132,6 +151,10 @@ jobs: table afterGc echo >> ./output.md + echo "### After Request" >> ./output.md + table afterRequest + echo >> ./output.md + # Determine if this is a significant change (more than 5% increase) if [ "$(echo "$RES" | jq -r '.afterGc.VmRSS.diff_percent | tonumber > 5')" = "true" ]; then echo "⚠️ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md diff --git a/packages/backend/scripts/measure-memory.mjs b/packages/backend/scripts/measure-memory.mjs index 749f550bcc..3f30e24fb4 100644 --- a/packages/backend/scripts/measure-memory.mjs +++ b/packages/backend/scripts/measure-memory.mjs @@ -14,6 +14,7 @@ import { fork } from 'node:child_process'; import { setTimeout } from 'node:timers/promises'; import { fileURLToPath } from 'node:url'; import { dirname, join } from 'node:path'; +import * as http from 'node:http'; import * as fs from 'node:fs/promises'; const __filename = fileURLToPath(import.meta.url); @@ -88,6 +89,40 @@ async function measureMemory() { process.stderr.write(`[server error] ${err}\n`); }); + async function triggerGc() { + const ok = new Promise((resolve) => { + serverProcess.once('message', (message) => { + if (message === 'gc ok') resolve(); + }); + }); + + serverProcess.send('gc'); + + await ok; + + await setTimeout(1000); + } + + function createRequest() { + return new Promise((resolve, reject) => { + const req = http.request({ + host: 'localhost', + port: 61812, + path: '/api/meta', + method: 'POST', + }, (res) => { + res.on('data', () => { }); + res.on('end', () => { + resolve(); + }); + }); + req.on('error', (err) => { + reject(err); + }); + req.end(); + }); + } + // Wait for server to be ready or timeout const startupStartTime = Date.now(); while (!serverReady) { @@ -108,17 +143,19 @@ async function measureMemory() { const beforeGc = await getMemoryUsage(pid); - serverProcess.send('gc'); + await triggerGc(); - await new Promise((resolve) => { - serverProcess.once('message', (message) => { - if (message === 'gc ok') resolve(); - }); - }); + const afterGc = await getMemoryUsage(pid); - await setTimeout(1000); + // create some http requests to simulate load + const REQUEST_COUNT = 10; + await Promise.all( + Array.from({ length: REQUEST_COUNT }).map(() => createRequest()), + ); - const afterGc = await getMemoryUsage(pid); + await triggerGc(); + + const afterRequest = await getMemoryUsage(pid); // Stop the server serverProcess.kill('SIGTERM'); @@ -143,6 +180,7 @@ async function measureMemory() { timestamp: new Date().toISOString(), beforeGc, afterGc, + afterRequest, }; return result; @@ -159,21 +197,25 @@ async function main() { // Calculate averages const beforeGc = structuredClone(keys); const afterGc = structuredClone(keys); + const afterRequest = structuredClone(keys); for (const res of results) { for (const key of Object.keys(keys)) { beforeGc[key] += res.beforeGc[key]; afterGc[key] += res.afterGc[key]; + afterRequest[key] += res.afterRequest[key]; } } for (const key of Object.keys(keys)) { beforeGc[key] = Math.round(beforeGc[key] / SAMPLE_COUNT); afterGc[key] = Math.round(afterGc[key] / SAMPLE_COUNT); + afterRequest[key] = Math.round(afterRequest[key] / SAMPLE_COUNT); } const result = { timestamp: new Date().toISOString(), beforeGc, afterGc, + afterRequest, }; // Output as JSON to stdout |