simple-web-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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