Co-authored-by: ajnart <49837342+ajnart@users.noreply.github.com>
149 lines
4.4 KiB
Bash
Executable File
149 lines
4.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Benchmark memory usage: separate ws server vs integrated custom Next.js server
|
|
# Usage: ./scripts/benchmark-memory.sh [approach] [wait_seconds]
|
|
# approach: "separate" | "integrated" | "both" (default: both)
|
|
|
|
set -e
|
|
|
|
APPROACH="${1:-both}"
|
|
WAIT_SECONDS="${2:-15}"
|
|
|
|
measure_process_tree_memory() {
|
|
local root_pid=$1
|
|
local label=$2
|
|
local total_rss=0
|
|
|
|
if [ -z "$root_pid" ] || ! kill -0 "$root_pid" 2>/dev/null; then
|
|
echo "$label: not running"
|
|
return
|
|
fi
|
|
|
|
# Measure root process
|
|
local root_rss
|
|
root_rss=$(grep VmRSS /proc/$root_pid/status 2>/dev/null | awk '{print $2}')
|
|
root_rss=${root_rss:-0}
|
|
total_rss=$root_rss
|
|
local root_mb
|
|
root_mb=$(echo "scale=2; $root_rss / 1024" | bc)
|
|
echo " $label (PID $root_pid): ${root_mb} MB"
|
|
|
|
# Measure child processes recursively
|
|
for cpid in $(pgrep -P "$root_pid" 2>/dev/null); do
|
|
if kill -0 "$cpid" 2>/dev/null; then
|
|
local child_rss
|
|
child_rss=$(grep VmRSS /proc/$cpid/status 2>/dev/null | awk '{print $2}')
|
|
child_rss=${child_rss:-0}
|
|
total_rss=$((total_rss + child_rss))
|
|
local child_mb
|
|
child_mb=$(echo "scale=2; $child_rss / 1024" | bc)
|
|
local child_cmd
|
|
child_cmd=$(cat /proc/$cpid/cmdline 2>/dev/null | tr '\0' ' ' | head -c 60)
|
|
echo " Child (PID $cpid): ${child_mb} MB - $child_cmd"
|
|
|
|
# Grandchildren
|
|
for gpid in $(pgrep -P "$cpid" 2>/dev/null); do
|
|
if kill -0 "$gpid" 2>/dev/null; then
|
|
local gchild_rss
|
|
gchild_rss=$(grep VmRSS /proc/$gpid/status 2>/dev/null | awk '{print $2}')
|
|
gchild_rss=${gchild_rss:-0}
|
|
total_rss=$((total_rss + gchild_rss))
|
|
local gchild_mb
|
|
gchild_mb=$(echo "scale=2; $gchild_rss / 1024" | bc)
|
|
local gchild_cmd
|
|
gchild_cmd=$(cat /proc/$gpid/cmdline 2>/dev/null | tr '\0' ' ' | head -c 60)
|
|
echo " Grandchild (PID $gpid): ${gchild_mb} MB - $gchild_cmd"
|
|
fi
|
|
done
|
|
fi
|
|
done
|
|
|
|
local total_mb
|
|
total_mb=$(echo "scale=2; $total_rss / 1024" | bc)
|
|
echo " Subtotal: ${total_mb} MB"
|
|
# Export for caller
|
|
eval "${label}_TOTAL_RSS=$total_rss"
|
|
}
|
|
|
|
cleanup_pids() {
|
|
for pid in "$@"; do
|
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
kill "$pid" 2>/dev/null || true
|
|
fi
|
|
done
|
|
wait 2>/dev/null || true
|
|
}
|
|
|
|
run_separate() {
|
|
echo "============================================"
|
|
echo "SEPARATE APPROACH (Current: WS + Next.js)"
|
|
echo "============================================"
|
|
|
|
# Start WS server
|
|
node apps/websocket/wssServer.cjs &
|
|
WS_PID=$!
|
|
sleep 5
|
|
|
|
WS_LISTEN_PID=$(lsof -i :3001 -t 2>/dev/null | head -1)
|
|
echo "WS server listening PID: $WS_LISTEN_PID"
|
|
|
|
WS_RSS=$(grep VmRSS /proc/${WS_LISTEN_PID}/status 2>/dev/null | awk '{print $2}')
|
|
WS_RSS=${WS_RSS:-0}
|
|
WS_MB=$(echo "scale=2; $WS_RSS / 1024" | bc)
|
|
echo " WebSocket Server: ${WS_MB} MB"
|
|
|
|
echo ""
|
|
echo "TOTAL (Separate WS only): ${WS_MB} MB"
|
|
echo "Note: Next.js dev server not included (would add ~1.5-2.5 GB)"
|
|
echo "============================================"
|
|
|
|
cleanup_pids "$WS_PID"
|
|
SEPARATE_RSS=$WS_RSS
|
|
}
|
|
|
|
run_integrated() {
|
|
echo "============================================"
|
|
echo "INTEGRATED APPROACH (Custom Next.js Server)"
|
|
echo "============================================"
|
|
|
|
cd apps/nextjs
|
|
node customServer.cjs &
|
|
CUSTOM_PID=$!
|
|
cd ../..
|
|
|
|
echo "Waiting ${WAIT_SECONDS}s for server to stabilize..."
|
|
sleep "$WAIT_SECONDS"
|
|
|
|
measure_process_tree_memory "$CUSTOM_PID" "CustomServer"
|
|
echo ""
|
|
INTEGRATED_RSS=${CustomServer_TOTAL_RSS:-0}
|
|
INTEGRATED_MB=$(echo "scale=2; $INTEGRATED_RSS / 1024" | bc)
|
|
echo "TOTAL (Integrated): ${INTEGRATED_MB} MB"
|
|
echo "============================================"
|
|
|
|
cleanup_pids "$CUSTOM_PID"
|
|
}
|
|
|
|
if [ "$APPROACH" = "separate" ] || [ "$APPROACH" = "both" ]; then
|
|
run_separate
|
|
echo ""
|
|
fi
|
|
|
|
if [ "$APPROACH" = "integrated" ] || [ "$APPROACH" = "both" ]; then
|
|
# Clean up lock from previous run
|
|
rm -rf apps/nextjs/.next/dev/lock
|
|
run_integrated
|
|
echo ""
|
|
fi
|
|
|
|
if [ "$APPROACH" = "both" ]; then
|
|
echo "============================================"
|
|
echo "COMPARISON"
|
|
echo "============================================"
|
|
SEP_MB=$(echo "scale=2; ${SEPARATE_RSS:-0} / 1024" | bc)
|
|
INT_MB=$(echo "scale=2; ${INTEGRATED_RSS:-0} / 1024" | bc)
|
|
echo "Separate WS server only: ${SEP_MB} MB"
|
|
echo "Integrated custom server: ${INT_MB} MB"
|
|
echo "(The integrated server includes both Next.js AND WebSocket)"
|
|
echo "============================================"
|
|
fi
|