Skip to content

Commit 31fc935

Browse files
fix: clarify cl vs cache_length, add multi-run warning
- rename cl->ctx_len in scripts (was confusing with -cl flag) - print cache_length in output for clarity - force runs=1 for LLaMA only (clear() is no-op, Qwen3 unaffected) - update README with CTX_LENS and RUNS limitation note per @jialilve feedback
1 parent 27db797 commit 31fc935

4 files changed

Lines changed: 56 additions & 43 deletions

File tree

tools/mllm-llm-benchmark/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,16 @@ Output goes to `bench_context/context_sweep_v2.csv`.
5353
- `MODEL`: Path to model file (required)
5454
- `CFG`: Path to config json (default: `./examples/llama/config_tiny_llama.json`)
5555
- `THREADS`: Number of threads (default: 8)
56-
- `RUNS`: How many runs to average (default: 1)
56+
- `RUNS`: How many runs to average (default: 1, LLaMA models auto-limited to 1)
5757
- `COOLDOWN`: Seconds to wait between runs (default: 0)
58-
- `CLS`: Context lengths to test (default: "256 512 1024 2048 4096")
58+
- `CTX_LENS`: Context lengths to test (default: "256 512 1024 2048 4096")
5959
- `TG_DH`: Generate length for decode_heavy mode (default: 256)
6060
- `TG_TTFT`: Generate length for prefill_ttft mode (default: 2)
6161
- `OUTDIR`: Output directory (default: bench_context)
6262

6363
**Test modes:**
64-
- `prefill_ttft`: Measures time to first token (prompt length = CL-2, generates 2 tokens)
65-
- `decode_heavy`: Measures decode throughput (prompt length = CL-256, generates 256 tokens)
64+
- `prefill_ttft`: Measures time to first token (prompt length = CTX_LEN-2, generates 2 tokens)
65+
- `decode_heavy`: Measures decode throughput (prompt length = CTX_LEN-256, generates 256 tokens)
6666

6767
### Plot Results
6868

tools/mllm-llm-benchmark/main.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,20 +78,32 @@ MLLM_MAIN({
7878
return 1;
7979
}
8080

81+
std::string m_name = model_name.get();
82+
std::transform(m_name.begin(), m_name.end(), m_name.begin(),
83+
[](unsigned char c) { return std::tolower(c); });
84+
if (R > 1 && (m_name.find("llama") != std::string::npos ||
85+
m_name.find("tiny_llama") != std::string::npos)) {
86+
mllm::print("[WARN] KV-cache reset not available for LLaMA yet");
87+
mllm::print("[WARN] Forcing runs=1 to prevent cache corruption");
88+
R = 1;
89+
90+
}
91+
8192
std::ofstream csv_file;
8293
if (!output_csv.get().empty()) {
8394
csv_file.open(output_csv.get());
8495
if (!csv_file.is_open()) {
8596
mllm::print("[ERROR] Failed to open --output_csv:", output_csv.get());
8697
return 1;
8798
}
88-
csv_file << "schema_version,git_commit,arch,model_name,pp,tg,ttft_ms,prefill_speed,decode_speed,prefill_ms,decode_ms_per_"
99+
csv_file << "schema_version,git_commit,arch,model_name,cache_length,pp,tg,ttft_ms,prefill_speed,decode_speed,prefill_ms,decode_ms_per_"
89100
"tok,kv_est_bytes_pp,kv_est_bytes_final\n";
90101
}
91102

92103
mllm::print("Model Info");
93104
benchmark->init(config_path.get(), model_path.get(), cache_length.get());
94105
benchmark->printModelInfo();
106+
mllm::print("Cache Length :", cache_length.get());
95107

96108
// Warmup run
97109
mllm::print("Warmup Run");
@@ -202,7 +214,7 @@ MLLM_MAIN({
202214

203215
std::stringstream ss;
204216
ss << schema_version.get() << "," << STRINGIFY(MLLM_GIT_COMMIT_HASH) << "," << mllm::cpu::CURRENT_ARCH_STRING << ","
205-
<< model_name.get() << "," << pp << "," << tg << "," << avg_ttft << "," << avg_prefill_speed << "," << avg_decode_speed
217+
<< model_name.get() << "," << cache_length.get() << "," << pp << "," << tg << "," << avg_ttft << "," << avg_prefill_speed << "," << avg_decode_speed
206218
<< "," << avg_prefill_ms << "," << avg_decode_ms_per_tok << "," << kv_est_bytes_pp << "," << kv_est_bytes_final;
207219

208220
if (csv_file.is_open()) { csv_file << ss.str() << std::endl; }

tools/mllm-llm-benchmark/scripts/plot_sweep.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ def to_int(x):
2020
rows.append(row)
2121

2222
# normalize numeric fields
23-
num_fields = ["cl","pp","tg","threads","ttft_ms","prefill_ms","decode_ms","decode_ms_per_tok","peak_rss_kb","kv_est_kb"]
23+
num_fields = ["ctx_len","pp","tg","threads","ttft_ms","prefill_ms","decode_ms","decode_ms_per_tok","peak_rss_kb","kv_est_kb"]
2424
for row in rows:
2525
for k in num_fields:
2626
if k in row:
@@ -29,13 +29,13 @@ def to_int(x):
2929
# write summary
3030
stamp = os.path.splitext(os.path.basename(csv_path))[0]
3131
summary_path = os.path.join(out_dir, f"{stamp}.summary.csv")
32-
fieldnames = ["ts","git","arch","model","mode","cl","pp","tg","threads",
32+
fieldnames = ["ts","git","arch","model","mode","ctx_len","pp","tg","threads",
3333
"ttft_ms","prefill_ms","decode_ms","decode_ms_per_tok",
3434
"peak_rss_kb","kv_est_kb","peak_rss_gb","kv_est_mb"]
3535
with open(summary_path, "w", newline="") as f:
3636
w = csv.DictWriter(f, fieldnames=fieldnames)
3737
w.writeheader()
38-
for row in sorted(rows, key=lambda x: (x.get("mode",""), x.get("cl",0))):
38+
for row in sorted(rows, key=lambda x: (x.get("mode",""), x.get("ctx_len",0))):
3939
peak_rss_kb = row.get("peak_rss_kb", float("nan"))
4040
kv_est_kb = row.get("kv_est_kb", float("nan"))
4141
out = {k: row.get(k, "") for k in fieldnames}
@@ -67,32 +67,32 @@ def plot_mode(mode, xkey, ykey, ylabel, fname):
6767
plt.savefig(os.path.join(out_dir, fname), dpi=180)
6868
plt.close()
6969

70-
plot_mode("prefill_ttft", "cl", "ttft_ms", "TTFT (ms)", f"{stamp}.prefill_ttft.ttft_ms.png")
71-
plot_mode("prefill_ttft", "cl", "prefill_ms", "Prefill latency (ms)", f"{stamp}.prefill_ttft.prefill_ms.png")
72-
plot_mode("decode_heavy", "cl", "decode_ms_per_tok", "Decode latency per token (ms)", f"{stamp}.decode_heavy.decode_ms_per_tok.png")
73-
plot_mode("decode_heavy", "cl", "decode_ms", "Decode latency total (ms)", f"{stamp}.decode_heavy.decode_ms.png")
70+
plot_mode("prefill_ttft", "ctx_len", "ttft_ms", "TTFT (ms)", f"{stamp}.prefill_ttft.ttft_ms.png")
71+
plot_mode("prefill_ttft", "ctx_len", "prefill_ms", "Prefill latency (ms)", f"{stamp}.prefill_ttft.prefill_ms.png")
72+
plot_mode("decode_heavy", "ctx_len", "decode_ms_per_tok", "Decode latency per token (ms)", f"{stamp}.decode_heavy.decode_ms_per_tok.png")
73+
plot_mode("decode_heavy", "ctx_len", "decode_ms", "Decode latency total (ms)", f"{stamp}.decode_heavy.decode_ms.png")
7474

7575
# memory plots
7676
mem = {}
7777
for row in rows:
78-
cl = row.get("cl", float("nan"))
79-
if cl != cl:
78+
ctx_len = row.get("ctx_len", float("nan"))
79+
if ctx_len != ctx_len:
8080
continue
81-
cl = int(cl)
81+
ctx_len = int(ctx_len)
8282
peak = row.get("peak_rss_kb", float("nan"))
8383
kv = row.get("kv_est_kb", float("nan"))
84-
cur = mem.get(cl, {"peak": float("nan"), "kv": float("nan")})
84+
cur = mem.get(ctx_len, {"peak": float("nan"), "kv": float("nan")})
8585
if peak==peak and (cur["peak"]!=cur["peak"] or peak>cur["peak"]): cur["peak"]=peak
8686
if kv==kv and (cur["kv"]!=cur["kv"] or kv>cur["kv"]): cur["kv"]=kv
87-
mem[cl]=cur
87+
mem[ctx_len]=cur
8888

89-
cls = sorted(mem.keys())
90-
peak_gb = [(mem[c]["peak"]/(1024*1024)) if mem[c]["peak"]==mem[c]["peak"] else float("nan") for c in cls]
91-
kv_mb = [(mem[c]["kv"]/1024) if mem[c]["kv"]==mem[c]["kv"] else float("nan") for c in cls]
89+
ctx_lens = sorted(mem.keys())
90+
peak_gb = [(mem[c]["peak"]/(1024*1024)) if mem[c]["peak"]==mem[c]["peak"] else float("nan") for c in ctx_lens]
91+
kv_mb = [(mem[c]["kv"]/1024) if mem[c]["kv"]==mem[c]["kv"] else float("nan") for c in ctx_lens]
9292

9393
plt.figure()
94-
plt.plot(cls, peak_gb, marker="o")
95-
plt.xlabel("cl")
94+
plt.plot(ctx_lens, peak_gb, marker="o")
95+
plt.xlabel("ctx_len")
9696
plt.ylabel("Peak RSS (GB)")
9797
plt.xscale("log", base=2)
9898
plt.grid(True, which="both", linestyle="--", linewidth=0.5)
@@ -101,8 +101,8 @@ def plot_mode(mode, xkey, ykey, ylabel, fname):
101101
plt.close()
102102

103103
plt.figure()
104-
plt.plot(cls, kv_mb, marker="o")
105-
plt.xlabel("cl")
104+
plt.plot(ctx_lens, kv_mb, marker="o")
105+
plt.xlabel("ctx_len")
106106
plt.ylabel("KV estimate (MB)")
107107
plt.xscale("log", base=2)
108108
plt.grid(True, which="both", linestyle="--", linewidth=0.5)

tools/mllm-llm-benchmark/scripts/sweep_context_v2.sh

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ RUNS="${RUNS:-1}"
99
COOLDOWN="${COOLDOWN:-0}"
1010
TG_DH="${TG_DH:-256}"
1111
TG_TTFT="${TG_TTFT:-2}"
12-
CLS="${CLS:-256 512 1024 2048 4096}"
12+
CTX_LENS="${CTX_LENS:-256 512 1024 2048 4096}"
1313
OUTDIR="${OUTDIR:-bench_context}"
1414

1515
mkdir -p "$OUTDIR"
1616
OUTCSV="$OUTDIR/context_sweep_v2.csv"
1717

18-
echo "ts,git,arch,model,mode,cl,pp,tg,threads,ttft_ms,prefill_ms,decode_ms,decode_ms_per_tok,peak_rss_kb,kv_est_kb" > "$OUTCSV"
18+
echo "ts,git,arch,model,mode,ctx_len,pp,tg,threads,ttft_ms,prefill_ms,decode_ms,decode_ms_per_tok,peak_rss_kb,kv_est_kb" > "$OUTCSV"
1919

2020
GIT="$(git rev-parse --short=12 HEAD 2>/dev/null || echo NA)"
2121
ARCH="$(uname -m)"
@@ -25,47 +25,48 @@ kv_est_kb() {
2525
python3 - <<'PY'
2626
import json, os, math
2727
cfg = os.environ["CFG"]
28-
cl = int(os.environ["CL"])
28+
ctx_len = int(os.environ["CTX_LEN"])
2929
bpe = int(os.environ.get("KV_BYTES_PER_ELEM","2"))
3030
j = json.load(open(cfg,"r"))
3131
L = int(j["num_hidden_layers"])
3232
H = int(j["num_attention_heads"])
3333
KVH = int(j.get("num_key_value_heads", H))
3434
hidden = int(j["hidden_size"])
3535
head_dim = hidden // H
36-
kv_bytes = 2 * L * KVH * head_dim * cl * bpe
36+
kv_bytes = 2 * L * KVH * head_dim * ctx_len * bpe
3737
print(int(math.ceil(kv_bytes / 1024)))
3838
PY
3939
}
4040

4141
run_one () {
4242
local mode="$1"
43-
local cl="$2"
43+
local ctx_len="$2"
4444
local tg="$3"
4545

46-
if (( cl <= tg )); then
47-
echo "skip: cl=$cl <= tg=$tg (mode=$mode)"
46+
if (( ctx_len <= tg )); then
47+
echo "skip: ctx_len=$ctx_len <= tg=$tg (mode=$mode)"
4848
return 0
4949
fi
5050

51-
local pp=$((cl - tg))
51+
local pp=$((ctx_len - tg))
5252
if (( pp < 1 )); then pp=1; fi
5353

54-
echo "==== mode=$mode cl=$cl pp=$pp tg=$tg ===="
54+
echo "==== mode=$mode ctx_len=$ctx_len pp=$pp tg=$tg ===="
5555

56-
local ALLLOG="$OUTDIR/run_${mode}_cl${cl}.all"
57-
local TIMELOG="$OUTDIR/run_${mode}_cl${cl}.time"
56+
local ALLLOG="$OUTDIR/run_${mode}_ctx${ctx_len}.all"
57+
local TIMELOG="$OUTDIR/run_${mode}_ctx${ctx_len}.time"
5858

5959
set +e
60+
# pass ctx as cache limit
6061
/usr/bin/time -v \
6162
"$BIN" -n tiny_llama -m "$MODEL" -c "$CFG" \
62-
-pp "$pp" -tg "$tg" -t "$THREADS" -cl "$cl" -r "$RUNS" -cs "$COOLDOWN" \
63+
-pp "$pp" -tg "$tg" -t "$THREADS" -cl "$ctx_len" -r "$RUNS" -cs "$COOLDOWN" \
6364
>"$ALLLOG" 2>"$TIMELOG"
6465
local EXIT_CODE=$?
6566
set -e
6667

6768
if [ $EXIT_CODE -ne 0 ]; then
68-
echo "run failed with exit code $EXIT_CODE: mode=$mode cl=$cl"
69+
echo "run failed with exit code $EXIT_CODE: mode=$mode ctx_len=$ctx_len"
6970
return 1
7071
fi
7172

@@ -78,16 +79,16 @@ run_one () {
7879
DECODE_PER_TOK="$(python3 -c "tg=float('$tg'); d=float('$DECODE_MS'); print(d/tg if tg>0 else 0.0)")"
7980

8081
PEAK_RSS_KB="$(grep -oP 'Maximum resident set size \(kbytes\):\s*\K[0-9]+' "$TIMELOG" | head -n 1 || echo 0)"
81-
KV_EST_KB="$(CFG="$CFG" CL="$cl" KV_BYTES_PER_ELEM="${KV_BYTES_PER_ELEM:-2}" kv_est_kb || echo 0)"
82+
KV_EST_KB="$(CFG="$CFG" CTX_LEN="$ctx_len" KV_BYTES_PER_ELEM="${KV_BYTES_PER_ELEM:-2}" kv_est_kb || echo 0)"
8283

8384
echo "TTFT=$TTFT_MS ms Prefill=$PREFILL_MS ms Decode=$DECODE_MS ms Decode/tok=$DECODE_PER_TOK ms peakRSS=$PEAK_RSS_KB KB KV_est=$KV_EST_KB KB"
8485

85-
echo "$TS,$GIT,$ARCH,tiny_llama,$mode,$cl,$pp,$tg,$THREADS,$TTFT_MS,$PREFILL_MS,$DECODE_MS,$DECODE_PER_TOK,$PEAK_RSS_KB,$KV_EST_KB" >> "$OUTCSV"
86+
echo "$TS,$GIT,$ARCH,tiny_llama,$mode,$ctx_len,$pp,$tg,$THREADS,$TTFT_MS,$PREFILL_MS,$DECODE_MS,$DECODE_PER_TOK,$PEAK_RSS_KB,$KV_EST_KB" >> "$OUTCSV"
8687
}
8788

88-
for CL in $CLS; do
89-
run_one "decode_heavy" "$CL" "$TG_DH"
90-
run_one "prefill_ttft" "$CL" "$TG_TTFT"
89+
for CTX in $CTX_LENS; do
90+
run_one "decode_heavy" "$CTX" "$TG_DH"
91+
run_one "prefill_ttft" "$CTX" "$TG_TTFT"
9192
done
9293

9394
echo

0 commit comments

Comments
 (0)