Files
spring-boot-demo/excel-export/scripts/measure.sh
T

52 lines
2.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Library: run ONE export in a fresh JVM with a fixed heap and print one result line.
# measure LABEL URL_PATH XMX [SAVE_TO_FILE]
# Every call starts its own JVM, so the numbers of one approach never contaminate another.
# Needs: curl, awk, a built jar (mvn package), Linux (/proc).
set -u
JAR="${JAR:-target/excel-export-1.0.0.jar}"
PORT="${PORT:-$((30000 + RANDOM % 20000))}"
WORK="${WORK:-/tmp/excel-export-measure}"
measure() {
local label="$1" path="$2" xmx="$3" save="${4:-/dev/null}"
rm -rf "$WORK"; mkdir -p "$WORK/tmp"
java -Xms"$xmx" -Xmx"$xmx" -XX:+UseG1GC -Xlog:gc:file="$WORK/gc.log" -XX:OnOutOfMemoryError="touch $WORK/oom" \
-Djava.io.tmpdir="$WORK/tmp" -jar "$JAR" --server.port="$PORT" > "$WORK/app.log" 2>&1 &
local pid=$!
for _ in $(seq 1 400); do [ "$(curl -s "http://localhost:$PORT/probe/ping")" = ok ] && break; sleep 0.5; done
# sample the size of the temp directory while the download runs
( peak=0; while kill -0 "$pid" 2>/dev/null && [ ! -f "$WORK/done" ]; do
s=$(du -sk "$WORK/tmp" 2>/dev/null | cut -f1); [ "${s:-0}" -gt "$peak" ] && peak=$s; echo "$peak" > "$WORK/tmp.peak"; sleep 0.2
done ) &
local sampler=$!
local res
local body="$WORK/body.txt"; [ "$save" = /dev/null ] && save="$body"
res=$(curl -s --max-time "${MAX_TIME:-300}" -o "$save" -w "%{http_code} %{size_download} %{time_total}" "http://localhost:$PORT$path"; echo " curl_exit=$?")
touch "$WORK/done"; wait "$sampler" 2>/dev/null || true
local http bytes errbody="" secs cexit probe peakUsed rss
read -r http bytes secs _ <<< "$res"
cexit=$(echo "$res" | sed 's/.*curl_exit=//')
probe=$(curl -s --max-time 5 "http://localhost:$PORT/probe" || true)
peakUsed=$(echo "$probe" | sed -n 's/.*"peakUsedHeapMb":\([0-9]*\).*/\1/p')
rss=$(awk '/VmHWM/ {printf "%d", $2/1024}' "/proc/$pid/status" 2>/dev/null)
local tmpafter; tmpafter=$(find "$WORK/tmp" -type f 2>/dev/null | wc -l)
local oom=no; [ -f "$WORK/oom" ] && oom=YES
[ "$http" != 200 ] && [ -f "$body" ] && errbody=" | body: $(head -c 120 "$body" | tr -d '\n')"
kill "$pid" 2>/dev/null || true; wait "$pid" 2>/dev/null || true
# largest heap occupancy right after a collection, number of pauses, longest pause
local gc
gc=$(grep -oE '[0-9]+M->[0-9]+M\([0-9]+M\) [0-9.]+ms' "$WORK/gc.log" | tr '>()M-' ' ' | sed 's/ms//' \
| awk '{ if ($2>a) a=$2; n++; if ($4>p) p=$4 } END { printf "%d %d %.0f", a, n, p }')
local maxafter pauses maxpause; read -r maxafter pauses maxpause <<< "$gc"
local tmppeak; tmppeak=$(( $(cat "$WORK/tmp.peak" 2>/dev/null || echo 0) / 1024 ))
printf '%-7s %-34s Xmx=%-5s http=%-3s curl=%-2s bytes=%-10s %6.1fs | peak used heap %5s MB | max after GC %5s MB | %4s GC pauses, longest %4s ms | peak RSS %5s MB | temp dir peak %4s MB, files left %s | OOM=%s%s\n' \
"$label" "$path" "$xmx" "$http" "$cexit" "$bytes" "$secs" "${peakUsed:--}" "$maxafter" "$pauses" "$maxpause" "${rss:--}" "$tmppeak" "$tmpafter" "$oom" "$errbody"
}