Files
serverAppConfigs/llm/scripts/bench-kairic-ab.sh
T
Frank 918fe4eaec Merge vllmScripts under llm/ (history-preserving import)
The vllmScripts repository (LLM inference fleet: serve scripts, systemd
units, env tunables, deployment runbook, research docs) is merged into
this repository. Its full history is grafted under llm/ with a
two-parent merge commit so no commit is lost.

A follow-up commit reorganizes llm/ into the repo layout:
llm/docs -> docs/LLM, llm/scripts -> scripts, llm/old -> old.
2026-08-22 15:03:03 -07:00

154 lines
6.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# bench-kairic-ab.sh — A/B perf isolation for the Kairic Edge deployment on
# Dankclaw. Run this ON DANKCLAW (paths are absolute target paths).
#
# Configs:
# runner pinned runner profile (b2048/ub512, reasoning off, target
# greedy argmax fast path ON)
# nommap runner + --no-mmap
# nofast runner + fast path OFF
# prod production profile (b4096/ub4096, --no-mmap, reasoning on/deepseek,
# fast path OFF, preserve_thinking)
# prod2048 prod with the pinned runner's batch sizes (b2048/ub512)
# prodnommap (obsolete: identical to prod since ubatch 4096 + --no-mmap
# moved into the production profile)
#
# Usage: ./scripts/bench-kairic-ab.sh <cfg> [ctx] [prompt_chars]
# Example: ./scripts/bench-kairic-ab.sh prod 16384 53000
#
# The server runs on scratch port 7893. STOP frank-default-large before
# benchmarking (see AGENTS.md). The server is killed on exit.
set -uo pipefail
CFG="${1:?runner|nofast|prod}"
CTX="${2:-32768}"
PCHARS="${3:-11000}"
PORT=7893
BIN=/home/dank/ciru-qwen38/ROCmFPX-kairic/build-kairic/bin/llama-server
MDIR=/home/dank/models/Kairic-Qwen3.8-27B-IU4-Edge
SDK=/home/dank/ling3-ciru/Ling-3.0-Flash-CIRU-int4-Strix-native/.venv/lib/python3.12/site-packages
LOG=/tmp/kairic-ab-$CFG.log
: > "$LOG"
export ROCM_PATH="$SDK/_rocm_sdk_devel"
export LD_LIBRARY_PATH="$(dirname "$BIN"):$SDK/_rocm_sdk_libraries/lib:$SDK/_rocm_sdk_core/lib:$SDK/_rocm_sdk_devel/lib"
export HIP_VISIBLE_DEVICES=0
export HSA_OVERRIDE_GFX_VERSION=11.5.1
export GGML_CUDA_GRAPH_OPT=0
export LLAMA_MTP_CPU_ARGMAX_FASTPATH=1
export PROMPTFORGE_TARGET_ONLY=0
export PROMPTFORGE_MODE=iu4_ffn
export PROMPTFORGE_IU4_SIDECAR="$MDIR/Qwen3.8-27B-Kairic-IU4-FFN.pfs"
export PROMPTFORGE_SIDECAR="$MDIR/Qwen3.8-27B-Kairic-IU4-FFN.pfs"
export PROMPTFORGE_IU4_HADAMARD=1
export PROMPTFORGE_IU4_SEGMENTED=0
export PROMPTFORGE_ENABLE_FFN_KEEPERS=0
export PROMPTFORGE_FFN_KEEPERS=late6
export PROMPTFORGE_ENABLE_GDN=1
export PROMPTFORGE_ENABLE_GDN_W8=0
export PROMPTFORGE_GDN_SIDECAR_OVERRIDE="$MDIR/Qwen3.8-27B-Kairic-IU4-GDN.pfs"
export PROMPTFORGE_GDN_SIDECAR="$MDIR/Qwen3.8-27B-Kairic-IU4-GDN.pfs"
export PROMPTFORGE_GDN_IU4_HADAMARD=1
export PROMPTFORGE_ENABLE_GDN_KEEPERS=0
export PROMPTFORGE_ENABLE_GDN_OUTPUT=1
export PROMPTFORGE_GDN_OUTPUT_SIDECAR="$MDIR/Qwen3.8-27B-Kairic-IU4-GDN-Output.pfs"
export PROMPTFORGE_GDN_OUTPUT_KEEPERS=v3_lateq6
export PROMPTFORGE_ENABLE_SMALLM_IU4=1
export PROMPTFORGE_ENABLE_SMALLM_GDN_IU4=1
export PROMPTFORGE_ENABLE_SMALLM_GDN_OUTPUT_IU4=0
export PROMPTFORGE_ENABLE_IU4_DECODE_M2_M5=0
export PROMPTFORGE_OUTPUT_K8_STRICT_GREEDY=0
MMAP=""
case "$CFG" in
runner) export LLAMA_TARGET_GREEDY_ARGMAX_FASTPATH=1; B=2048; UB=512; REA=off; RFMT=none; EXTRA="" ;;
nommap) export LLAMA_TARGET_GREEDY_ARGMAX_FASTPATH=1; B=2048; UB=512; REA=off; RFMT=none; EXTRA=""; MMAP="--no-mmap" ;;
nofast) export LLAMA_TARGET_GREEDY_ARGMAX_FASTPATH=0; B=2048; UB=512; REA=off; RFMT=none; EXTRA="" ;;
prod) export LLAMA_TARGET_GREEDY_ARGMAX_FASTPATH=0; B=4096; UB=4096; REA=on; RFMT=deepseek; EXTRA="--chat-template-kwargs {\"preserve_thinking\":\"true\"}"; MMAP="--no-mmap" ;;
prod2048) export LLAMA_TARGET_GREEDY_ARGMAX_FASTPATH=0; B=2048; UB=512; REA=on; RFMT=deepseek; EXTRA="--chat-template-kwargs {\"preserve_thinking\":\"true\"}"; MMAP="--no-mmap" ;;
prodnommap) export LLAMA_TARGET_GREEDY_ARGMAX_FASTPATH=0; B=4096; UB=2048; REA=on; RFMT=deepseek; EXTRA="--chat-template-kwargs {\"preserve_thinking\":\"true\"}"; MMAP="--no-mmap" ;;
esac
"$BIN" -m "$MDIR/Qwen3.8-27B-IU4-Kairic-Edge.gguf" \
--alias bench --host 127.0.0.1 --port "$PORT" --jinja \
-dev ROCm0 -ngl 999 -c "$CTX" -b "$B" -ub "$UB" -fa on -ctk f16 -ctv f16 \
-t 16 -tb 32 -np 1 -ctxcp 32 --cache-ram 8192 --cache-prompt --cache-idle-slots $MMAP \
--metrics --kairic-edge \
--spec-type draft-mtp --spec-draft-device ROCm0 --spec-draft-ngl 999 \
--spec-draft-type-k f16 --spec-draft-type-v f16 \
--spec-draft-n-max 4 --spec-draft-n-min 0 --spec-draft-p-min 0.0 --spec-draft-p-split 0.10 \
--spec-draft-backend-sampling \
--temp 0 --top-p 1.0 --top-k 0 --min-p 0.0 \
--reasoning "$REA" --reasoning-format "$RFMT" --reasoning-budget -1 \
$EXTRA >> "$LOG" 2>&1 &
SPID=$!
trap 'kill $SPID 2>/dev/null; wait $SPID 2>/dev/null' EXIT
for i in $(seq 1 300); do
kill -0 $SPID 2>/dev/null || { echo "SERVER DIED"; tail -20 "$LOG"; exit 2; }
curl -sf "http://127.0.0.1:$PORT/health" >/dev/null 2>&1 && break
sleep 2
done
echo "=== CFG=$CFG ready ==="
python3 - "$PORT" "$CFG" "$PCHARS" <<'PY'
import sys, json, time, urllib.request
port, cfg, pchars = sys.argv[1], sys.argv[2], int(sys.argv[3])
VAR = [
"narrative nonfiction blends observation with reflection, ",
"and a careful writer lets each clause earn its place ",
"in the sentence's rising line, so meaning accumulates slowly. ",
"The reader is not hurried; the reader is led. Loose and periodic, ",
"the style turns on concrete nouns and verbs that carry weight. ",
"A paragraph is not a list but a single turn of thought that ",
"opens, develops, and lands, and clarity is a courtesy owed ",
"to the willing reader who gives the writer their attention. ",
]
parts = []
t = 0
while len("".join(parts)) < pchars:
for k in range(3):
parts.append(VAR[(t + k) % len(VAR)])
parts.append(f" Note {t}. ")
t += 1
longtext = "".join(parts)
prompt = longtext + "\n\nNow write a long, detailed continuation of this essay (at least five paragraphs) about the philosophy of language.\n"
body = {
"model": "bench",
"prompt": prompt,
"max_tokens": 512,
"temperature": 0,
"top_p": 1.0,
"top_k": 0,
"min_p": 0.0,
"stream": False,
"cache_prompt": True,
}
# ignore_eos is rejected by the exact-Q8 greedy argmax fast path (runner cfg).
if cfg not in ("runner",):
body["ignore_eos"] = True
def run(tag):
req = urllib.request.Request(f"http://127.0.0.1:{port}/v1/completions",
data=json.dumps(body).encode(),
headers={"Content-Type": "application/json"})
t0 = time.time()
try:
with urllib.request.urlopen(req, timeout=3600) as resp:
out = json.load(resp)
except Exception as e:
body_txt = getattr(e, "read", lambda: b"")()
print(f"[{tag}] REQUEST FAILED: {e}")
print(f"[{tag}] body: {body_txt.decode('utf-8', 'ignore')[:500]}")
raise SystemExit(3)
wall = time.time() - t0
u = out.get("usage", {})
tm = out.get("timings", {})
pt = u.get("prompt_tokens", 0); ct = u.get("completion_tokens", 0)
pps = tm.get("prompt_per_second", 0); tps = tm.get("predicted_per_second", 0)
print(f"[{tag}] cfg={cfg} prompt={pt} completion={ct} prefill={pps:.1f} t/s decode={tps:.2f} t/s wall={wall:.1f}s")
run("cold")
run("warm")
PY
grep -E "print_timing|statistics" "$LOG" | tail -6
exit 0