summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2026-01-22 18:53:53 +0900
committerGitHub <noreply@github.com>2026-01-22 18:53:53 +0900
commita168e7b6486013d05ba836d9a1d084a7708c19fb (patch)
treea9f0a1803e2b32c5c17e0d693777f98c90a8b1b8
parentUpdate report-backend-memory.yml (diff)
downloadmisskey-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.yml33
-rw-r--r--packages/backend/scripts/measure-memory.mjs58
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