Skip to content

Commit 2fa6ecc

Browse files
syuiloCopilot
andauthored
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 <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
1 parent f744b57 commit 2fa6ecc

File tree

4 files changed

+102
-43
lines changed

4 files changed

+102
-43
lines changed

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

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,31 +54,48 @@ jobs:
5454
BASE_MEMORY=$(cat ./artifacts/memory-base.json)
5555
HEAD_MEMORY=$(cat ./artifacts/memory-head.json)
5656
57-
calc() {
58-
BASE=$(echo "$BASE_MEMORY" | jq -r '.memory.'"$1"' // 0')
59-
HEAD=$(echo "$HEAD_MEMORY" | jq -r '.memory.'"$1"' // 0')
60-
61-
DIFF=$((HEAD - BASE))
62-
if [ "$BASE" -gt 0 ]; then
63-
DIFF_PERCENT=$(echo "scale=2; ($DIFF * 100) / $BASE" | bc)
64-
else
65-
DIFF_PERCENT=0
66-
fi
67-
68-
# Convert KB to MB for readability
69-
BASE_MB=$(echo "scale=2; $BASE / 1024" | bc)
70-
HEAD_MB=$(echo "scale=2; $HEAD / 1024" | bc)
71-
DIFF_MB=$(echo "scale=2; $DIFF / 1024" | bc)
72-
73-
echo "$1-base=$BASE_MB" >> "$GITHUB_OUTPUT"
74-
echo "$1-head=$HEAD_MB" >> "$GITHUB_OUTPUT"
75-
echo "$1-diff=$DIFF_MB" >> "$GITHUB_OUTPUT"
76-
echo "$1-diff_percent=$DIFF_PERCENT" >> "$GITHUB_OUTPUT"
57+
variation() {
58+
calc() {
59+
BASE=$(echo "$BASE_MEMORY" | jq -r ".${1}.${2} // 0")
60+
HEAD=$(echo "$HEAD_MEMORY" | jq -r ".${1}.${2} // 0")
61+
62+
DIFF=$((HEAD - BASE))
63+
if [ "$BASE" -gt 0 ]; then
64+
DIFF_PERCENT=$(echo "scale=2; ($DIFF * 100) / $BASE" | bc)
65+
else
66+
DIFF_PERCENT=0
67+
fi
68+
69+
# Convert KB to MB for readability
70+
BASE_MB=$(echo "scale=2; $BASE / 1024" | bc)
71+
HEAD_MB=$(echo "scale=2; $HEAD / 1024" | bc)
72+
DIFF_MB=$(echo "scale=2; $DIFF / 1024" | bc)
73+
74+
JSON=$(jq -c -n \
75+
--arg base "$BASE_MB" \
76+
--arg head "$HEAD_MB" \
77+
--arg diff "$DIFF_MB" \
78+
--arg diff_percent "$DIFF_PERCENT" \
79+
'{base: $base, head: $head, diff: $diff, diff_percent: $diff_percent}')
80+
81+
echo "$JSON"
82+
}
83+
84+
JSON=$(jq -c -n \
85+
--argjson VmRSS "$(calc $1 VmRSS)" \
86+
--argjson VmHWM "$(calc $1 VmHWM)" \
87+
--argjson VmSize "$(calc $1 VmSize)" \
88+
'{VmRSS: $VmRSS, VmHWM: $VmHWM, VmSize: $VmSize}')
89+
90+
echo "$JSON"
7791
}
7892
79-
calc VmRSS
80-
calc VmHWM
81-
calc VmSize
93+
JSON=$(jq -c -n \
94+
--argjson beforeGc "$(variation beforeGc)" \
95+
--argjson afterGc "$(variation afterGc)" \
96+
'{beforeGc: $beforeGc, afterGc: $afterGc}')
97+
98+
echo "res=$JSON" >> "$GITHUB_OUTPUT"
8299
- id: build-comment
83100
name: Build memory comment
84101
run: |
@@ -88,15 +105,33 @@ jobs:
88105
echo "$HEADER" > ./output.md
89106
echo >> ./output.md
90107
91-
echo "| Metric | base | head | Diff |" >> ./output.md
92-
echo "|--------|------|------|------|" >> ./output.md
93-
echo "| RSS | ${{ steps.compare.outputs.VmRSS-base }} MB | ${{ steps.compare.outputs.VmRSS-head }} MB | ${{ steps.compare.outputs.VmRSS-diff }} MB (${{ steps.compare.outputs.VmRSS-diff_percent }}%) |" >> ./output.md
94-
echo "| HWM | ${{ steps.compare.outputs.VmHWM-base }} MB | ${{ steps.compare.outputs.VmHWM-head }} MB | ${{ steps.compare.outputs.VmHWM-diff }} MB (${{ steps.compare.outputs.VmHWM-diff_percent }}%) |" >> ./output.md
95-
echo "| VMS | ${{ steps.compare.outputs.VmSize-base }} MB | ${{ steps.compare.outputs.VmSize-head }} MB | ${{ steps.compare.outputs.VmSize-diff }} MB (${{ steps.compare.outputs.VmSize-diff_percent }}%) |" >> ./output.md
108+
table() {
109+
line() {
110+
BASE=$(echo "${{ steps.compare.outputs.res }}" | jq -r ".${1}.${2}.base")
111+
HEAD=$(echo "${{ steps.compare.outputs.res }}" | jq -r ".${1}.${2}.head")
112+
DIFF=$(echo "${{ steps.compare.outputs.res }}" | jq -r ".${1}.${2}.diff")
113+
DIFF_PERCENT=$(echo "${{ steps.compare.outputs.res }}" | jq -r ".${1}.${2}.diff_percent")
114+
115+
echo "| ${2} | ${BASE} MB | ${HEAD} MB | ${DIFF} MB (${DIFF_PERCENT}%) |" >> ./output.md
116+
}
117+
118+
echo "| Metric | base | head | Diff |" >> ./output.md
119+
echo "|--------|------|------|------|" >> ./output.md
120+
line $1 VmRSS
121+
line $1 VmHWM
122+
line $1 VmSize
123+
}
124+
125+
echo "### Before GC" >> ./output.md
126+
table beforeGc
127+
echo >> ./output.md
128+
129+
echo "### After GC" >> ./output.md
130+
table afterGc
96131
echo >> ./output.md
97132
98133
# Determine if this is a significant change (more than 5% increase)
99-
if [ "$(echo "${{ steps.compare.outputs.VmRSS-diff_percent }} > 5" | bc)" -eq 1 ]; then
134+
if [ "$(echo "${{ steps.compare.outputs.res }}" | jq -r '.afterGc.VmRSS.diff_percent | tonumber > 5')" = "true" ]; then
100135
echo "⚠️ **Warning**: Memory usage has increased by more than 5%. Please verify this is not an unintended change." >> ./output.md
101136
echo >> ./output.md
102137
fi

packages/backend/scripts/measure-memory.mjs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ async function measureMemory() {
6060
...process.env,
6161
NODE_ENV: 'production',
6262
MK_DISABLE_CLUSTERING: '1',
63-
MK_FORCE_GC: '1',
6463
},
6564
stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
65+
execArgv: [...process.execArgv, '--expose-gc'],
6666
});
6767

6868
let serverReady = false;
@@ -104,9 +104,21 @@ async function measureMemory() {
104104
// Wait for memory to settle
105105
await setTimeout(MEMORY_SETTLE_TIME);
106106

107-
// Get memory usage from the server process via /proc
108107
const pid = serverProcess.pid;
109-
const memoryInfo = await getMemoryUsage(pid);
108+
109+
const beforeGc = await getMemoryUsage(pid);
110+
111+
serverProcess.send('gc');
112+
113+
await new Promise((resolve) => {
114+
serverProcess.once('message', (message) => {
115+
if (message === 'gc ok') resolve();
116+
});
117+
});
118+
119+
await setTimeout(1000);
120+
121+
const afterGc = await getMemoryUsage(pid);
110122

111123
// Stop the server
112124
serverProcess.kill('SIGTERM');
@@ -129,7 +141,8 @@ async function measureMemory() {
129141

130142
const result = {
131143
timestamp: new Date().toISOString(),
132-
memory: memoryInfo,
144+
beforeGc,
145+
afterGc,
133146
};
134147

135148
return result;
@@ -144,19 +157,23 @@ async function main() {
144157
}
145158

146159
// Calculate averages
147-
const avgMemory = structuredClone(keys);
160+
const beforeGc = structuredClone(keys);
161+
const afterGc = structuredClone(keys);
148162
for (const res of results) {
149-
for (const key of Object.keys(avgMemory)) {
150-
avgMemory[key] += res.memory[key];
163+
for (const key of Object.keys(keys)) {
164+
beforeGc[key] += res.beforeGc[key];
165+
afterGc[key] += res.afterGc[key];
151166
}
152167
}
153-
for (const key of Object.keys(avgMemory)) {
154-
avgMemory[key] = Math.round(avgMemory[key] / SAMPLE_COUNT);
168+
for (const key of Object.keys(keys)) {
169+
beforeGc[key] = Math.round(beforeGc[key] / SAMPLE_COUNT);
170+
afterGc[key] = Math.round(afterGc[key] / SAMPLE_COUNT);
155171
}
156172

157173
const result = {
158174
timestamp: new Date().toISOString(),
159-
memory: avgMemory,
175+
beforeGc,
176+
afterGc,
160177
};
161178

162179
// Output as JSON to stdout

packages/backend/src/boot/entry.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,17 @@ if (!envOption.disableClustering) {
8686
ev.mount();
8787
}
8888

89-
if (envOption.forceGc && global.gc != null) {
90-
global.gc();
91-
}
89+
process.on('message', msg => {
90+
if (msg === 'gc') {
91+
if (global.gc != null) {
92+
logger.info('Manual GC triggered');
93+
global.gc();
94+
if (process.send != null) process.send('gc ok');
95+
} else {
96+
logger.warn('Manual GC requested but gc is not available. Start the process with --expose-gc to enable this feature.');
97+
}
98+
}
99+
});
92100

93101
readyRef.value = true;
94102

packages/backend/src/env.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ const envOption = {
1111
verbose: false,
1212
withLogTime: false,
1313
quiet: false,
14-
forceGc: false,
1514
};
1615

1716
for (const key of Object.keys(envOption) as (keyof typeof envOption)[]) {

0 commit comments

Comments
 (0)