bench.sh (3747B)
1 #!/usr/bin/env bash 2 set -euo pipefail 3 4 PORT=8005 5 DB_PATH=/tmp/swa-bench/app.db 6 ADDR="0.0.0.0:$PORT" 7 BASE="http://localhost:$PORT" 8 HEY=$(nix build nixpkgs#hey --print-out-paths --no-link 2>/dev/null)/bin/hey 9 SQLITE=$(nix build nixpkgs#sqlite --print-out-paths --no-link 2>/dev/null | head -1)/bin/sqlite3 10 11 # Build release 12 echo "Building release..." 13 nix develop -c cargo build --release 2>&1 | tail -1 14 15 # Clean start 16 pkill -f "simple-web-app" 2>/dev/null || true 17 sleep 1 18 rm -rf /tmp/swa-bench && mkdir -p /tmp/swa-bench 19 20 DB_PATH=$DB_PATH ADDR=$ADDR DEBUG=false \ 21 SMTP_ADDR=localhost:25 SMTP_FROM=x@x.com SITE_URL=$BASE \ 22 ./target/release/simple-web-app &>/dev/null & 23 sleep 2 24 25 # Register, verify, login 26 curl -s -o /dev/null -X POST -d "username=bench&email=bench@test.com&password=pass123&password_confirm=pass123" "$BASE/register" 27 $SQLITE $DB_PATH "UPDATE user SET email_verified=1;" 28 curl -s -c /tmp/swa-bench-cookies.txt -L -o /dev/null -X POST -d "email=bench@test.com&password=pass123" "$BASE/login" 29 COOKIE=$(grep session /tmp/swa-bench-cookies.txt | awk '{print $6"="$7}') 30 31 # Seed data 32 STORIES=${STORIES:-200} 33 COMMENTS_PER_STORY=${COMMENTS_PER_STORY:-5} 34 COMMENT_STORIES=20 35 36 echo "Seeding $STORIES stories, $((COMMENT_STORIES * COMMENTS_PER_STORY)) comments..." 37 SEED_FILE=$(mktemp) 38 { 39 echo "BEGIN;" 40 NOW=$(date +%s) 41 for i in $(seq 1 $STORIES); do 42 echo "INSERT INTO story (title, url, text, domain, published, language, created_by, score) VALUES ('Story $i about interesting things', 'https://example.com/$i', 'Body text for story $i with words for FTS.', 'example.com', $NOW, 'en', 1, $((RANDOM % 50)));" 43 done 44 for s in $(seq 1 $COMMENT_STORIES); do 45 for c in $(seq 1 $COMMENTS_PER_STORY); do 46 echo "INSERT INTO comment (story_id, parent_id, path, depth, text, created_by, created_at) VALUES ($s, NULL, '$c', 0, 'Comment $c on story $s with discussion text', 1, $NOW);" 47 done 48 done 49 echo "COMMIT;" 50 echo "INSERT INTO story_fts(story_fts) VALUES('rebuild');" 51 } > "$SEED_FILE" 52 $SQLITE $DB_PATH < "$SEED_FILE" 53 rm "$SEED_FILE" 54 55 echo "" 56 echo "=== Data ===" 57 $SQLITE $DB_PATH " 58 SELECT 'stories: ' || COUNT(*) FROM story; 59 SELECT 'comments: ' || COUNT(*) FROM comment; 60 SELECT 'users: ' || COUNT(*) FROM user; 61 " 62 63 MIN_REQUESTS=200 64 65 run() { 66 local label=$1 url=$2 c=$3 n=${4:-$((c * 50))} method=${5:-GET} extra="${6:-}" 67 # Ensure enough requests for stable measurement 68 if (( n < MIN_REQUESTS )); then n=$MIN_REQUESTS; fi 69 local result 70 result=$($HEY -n "$n" -c "$c" -m "$method" $extra "$url" 2>&1) 71 local rps=$(echo "$result" | grep "Requests/sec" | awk '{print $2}') 72 local avg=$(echo "$result" | grep "Average" | awk '{print $2}') 73 local p99=$(echo "$result" | grep "99%" | awk '{print $3}') 74 printf "%-20s c=%-4s %10s rps avg=%ss p99=%ss\n" "$label" "$c" "$rps" "$avg" "$p99" 75 } 76 77 # Warmup: prime page caches and mmap regions before measuring 78 echo "" 79 echo "Warming up..." 80 $HEY -n 500 -c 50 "$BASE/" > /dev/null 2>&1 81 $HEY -n 200 -c 10 -m POST -H "Cookie:$COOKIE" "$BASE/vote/story/1" > /dev/null 2>&1 82 83 echo "" 84 echo "=== READS ===" 85 for c in 10 100 500; do run "homepage" "$BASE/" $c; done 86 for c in 10 100 500; do run "story" "$BASE/story/1" $c; done 87 for c in 10 100; do run "search" "$BASE/search" $c $((c * 20)) POST "-d search=interesting -H Content-Type:application/x-www-form-urlencoded"; done 88 89 echo "" 90 echo "=== WRITES ===" 91 for c in 1 10 50; do run "vote" "$BASE/vote/story/1" $c $((c * 50)) POST "-H Cookie:$COOKIE"; done 92 for c in 1 10; do run "submit" "$BASE/submit" $c $((c * 20)) POST "-H Cookie:$COOKIE -d title=Bench&url=https://example.com/b&text=&tags="; done 93 94 echo "" 95 echo "=== CEILING ===" 96 run "static" "$BASE/static/datastar.js" 200 10000 97 98 # Cleanup 99 pkill -f "simple-web-app" 2>/dev/null || true