Skip to content

Commit a168e7b

Browse files
authored
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
1 parent 1adcb03 commit a168e7b

File tree

2 files changed

+78
-13
lines changed

2 files changed

+78
-13
lines changed

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,17 @@ jobs:
8585
--argjson VmRSS "$(calc $1 VmRSS)" \
8686
--argjson VmHWM "$(calc $1 VmHWM)" \
8787
--argjson VmSize "$(calc $1 VmSize)" \
88-
'{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize}')
88+
--argjson VmData "$(calc $1 VmData)" \
89+
'{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize, VmData: $VmData}')
8990
9091
echo "$JSON"
9192
}
9293
9394
JSON=$(jq -c -n \
9495
--argjson beforeGc "$(variation beforeGc)" \
9596
--argjson afterGc "$(variation afterGc)" \
96-
'{beforeGc: $beforeGc, afterGc: $afterGc}')
97+
--argjson afterRequest "$(variation afterRequest)" \
98+
'{beforeGc: $beforeGc, afterGc: $afterGc, afterRequest: $afterRequest}')
9799
98100
echo "res=$JSON" >> "$GITHUB_OUTPUT"
99101
- id: build-comment
@@ -108,20 +110,37 @@ jobs:
108110
echo >> ./output.md
109111
110112
table() {
113+
echo "| Metric | base (MB) | head (MB) | Diff (MB) | Diff (%) |" >> ./output.md
114+
echo "|--------|------:|------:|------:|------:|" >> ./output.md
115+
111116
line() {
117+
METRIC=$2
112118
BASE=$(echo "$RES" | jq -r ".${1}.${2}.base")
113119
HEAD=$(echo "$RES" | jq -r ".${1}.${2}.head")
114120
DIFF=$(echo "$RES" | jq -r ".${1}.${2}.diff")
115121
DIFF_PERCENT=$(echo "$RES" | jq -r ".${1}.${2}.diff_percent")
116122
117-
echo "| ${2} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB (${DIFF_PERCENT}%) |" >> ./output.md
123+
if (( $(echo "$DIFF_PERCENT > 0" | bc -l) )); then
124+
DIFF="+$DIFF"
125+
DIFF_PERCENT="+$DIFF_PERCENT"
126+
fi
127+
128+
# highlight VmRSS
129+
if [ "$2" = "VmRSS" ]; then
130+
METRIC="**${METRIC}**"
131+
BASE="**${BASE}**"
132+
HEAD="**${HEAD}**"
133+
DIFF="**${DIFF}**"
134+
DIFF_PERCENT="**${DIFF_PERCENT}**"
135+
fi
136+
137+
echo "| ${METRIC} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB | ${DIFF_PERCENT}% |" >> ./output.md
118138
}
119139
120-
echo "| Metric | base | head | Diff |" >> ./output.md
121-
echo "|--------|------|------|------|" >> ./output.md
122140
line $1 VmRSS
123141
line $1 VmHWM
124142
line $1 VmSize
143+
line $1 VmData
125144
}
126145
127146
echo "### Before GC" >> ./output.md
@@ -132,6 +151,10 @@ jobs:
132151
table afterGc
133152
echo >> ./output.md
134153
154+
echo "### After Request" >> ./output.md
155+
table afterRequest
156+
echo >> ./output.md
157+
135158
# Determine if this is a significant change (more than 5% increase)
136159
if [ "$(echo "$RES" | jq -r '.afterGc.VmRSS.diff_percent | tonumber > 5')" = "true" ]; then
137160
echo "⚠️ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md

packages/backend/scripts/measure-memory.mjs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { fork } from 'node:child_process';
1414
import { setTimeout } from 'node:timers/promises';
1515
import { fileURLToPath } from 'node:url';
1616
import { dirname, join } from 'node:path';
17+
import * as http from 'node:http';
1718
import * as fs from 'node:fs/promises';
1819

1920
const __filename = fileURLToPath(import.meta.url);
@@ -88,6 +89,40 @@ async function measureMemory() {
8889
process.stderr.write(`[server error] ${err}\n`);
8990
});
9091

92+
async function triggerGc() {
93+
const ok = new Promise((resolve) => {
94+
serverProcess.once('message', (message) => {
95+
if (message === 'gc ok') resolve();
96+
});
97+
});
98+
99+
serverProcess.send('gc');
100+
101+
await ok;
102+
103+
await setTimeout(1000);
104+
}
105+
106+
function createRequest() {
107+
return new Promise((resolve, reject) => {
108+
const req = http.request({
109+
host: 'localhost',
110+
port: 61812,
111+
path: '/api/meta',
112+
method: 'POST',
113+
}, (res) => {
114+
res.on('data', () => { });
115+
res.on('end', () => {
116+
resolve();
117+
});
118+
});
119+
req.on('error', (err) => {
120+
reject(err);
121+
});
122+
req.end();
123+
});
124+
}
125+
91126
// Wait for server to be ready or timeout
92127
const startupStartTime = Date.now();
93128
while (!serverReady) {
@@ -108,17 +143,19 @@ async function measureMemory() {
108143

109144
const beforeGc = await getMemoryUsage(pid);
110145

111-
serverProcess.send('gc');
146+
await triggerGc();
112147

113-
await new Promise((resolve) => {
114-
serverProcess.once('message', (message) => {
115-
if (message === 'gc ok') resolve();
116-
});
117-
});
148+
const afterGc = await getMemoryUsage(pid);
118149

119-
await setTimeout(1000);
150+
// create some http requests to simulate load
151+
const REQUEST_COUNT = 10;
152+
await Promise.all(
153+
Array.from({ length: REQUEST_COUNT }).map(() => createRequest()),
154+
);
120155

121-
const afterGc = await getMemoryUsage(pid);
156+
await triggerGc();
157+
158+
const afterRequest = await getMemoryUsage(pid);
122159

123160
// Stop the server
124161
serverProcess.kill('SIGTERM');
@@ -143,6 +180,7 @@ async function measureMemory() {
143180
timestamp: new Date().toISOString(),
144181
beforeGc,
145182
afterGc,
183+
afterRequest,
146184
};
147185

148186
return result;
@@ -159,21 +197,25 @@ async function main() {
159197
// Calculate averages
160198
const beforeGc = structuredClone(keys);
161199
const afterGc = structuredClone(keys);
200+
const afterRequest = structuredClone(keys);
162201
for (const res of results) {
163202
for (const key of Object.keys(keys)) {
164203
beforeGc[key] += res.beforeGc[key];
165204
afterGc[key] += res.afterGc[key];
205+
afterRequest[key] += res.afterRequest[key];
166206
}
167207
}
168208
for (const key of Object.keys(keys)) {
169209
beforeGc[key] = Math.round(beforeGc[key] / SAMPLE_COUNT);
170210
afterGc[key] = Math.round(afterGc[key] / SAMPLE_COUNT);
211+
afterRequest[key] = Math.round(afterRequest[key] / SAMPLE_COUNT);
171212
}
172213

173214
const result = {
174215
timestamp: new Date().toISOString(),
175216
beforeGc,
176217
afterGc,
218+
afterRequest,
177219
};
178220

179221
// Output as JSON to stdout

0 commit comments

Comments
 (0)