#!/bin/sh # bench-prefill.sh — measure llama-server prefill/decode scaling on :8083 # # Uses the server's own `timings` block (prompt_ms / predicted_ms), which is far # more accurate than wall clock. A unique nonce is placed FIRST in every prompt to # defeat llama.cpp prefix caching — otherwise cache_n>0 and prefill is not measured. URL=http://127.0.0.1:8083/v1/chat/completions OUT=/home/arduino/bench-prefill.json UNIT="The structural sensor node recorded a nominal vibration reading during the overnight monitoring window and logged it. " : > "$OUT" echo "size_label,prompt_n,prompt_ms,prefill_tps,predicted_n,predicted_ms,decode_tps,cache_n,wall_s" for reps in 12 25 50 100; do # build filler filler="" i=0 while [ $i -lt $reps ]; do filler="$filler$UNIT"; i=$((i+1)); done nonce="$(date +%s%N)$$" python3 - "$nonce" "$filler" > /tmp/payload.json <<'PY' import json,sys nonce, filler = sys.argv[1], sys.argv[2] content = f"[req-{nonce}] {filler}\n\nIn one short sentence, what is this text about?" print(json.dumps({"model":"qwen","max_tokens":16,"temperature":0, "messages":[{"role":"user","content":content}]})) PY start=$(date +%s) resp=$(curl -s --max-time 1800 "$URL" -H 'Content-Type: application/json' -d @/tmp/payload.json) end=$(date +%s) wall=$((end-start)) echo "$resp" >> "$OUT" echo "$resp" | jq -r --arg r "reps=$reps" --arg w "$wall" ' [$r, .timings.prompt_n, (.timings.prompt_ms|round), (.timings.prompt_per_second*100|round/100), .timings.predicted_n, (.timings.predicted_ms|round), (.timings.predicted_per_second*100|round/100), .timings.cache_n, $w] | @csv' done