Qwen3 Benchmark Harness

July 1, 2026 ยท View on GitHub

This directory contains the benchmark harness used for the Grout paper runs. It is intentionally separate from the normal grout inference CLI.

Contents

PathPurpose
src/bin/grout_bench.rsGrout timing binary. Built only with --features benchmarks.
bench_sglang.py, bench_vllm.py, bench_llama_cpp.py, bench_trtllm.pySingle-request wrappers for comparison engines.
sweep_tg*.shDecode-length sweeps at fixed prompt length.
sweep_pp*.shPrompt-length sweeps at fixed decode length.
aggregate_sweep.pyBuilds median/IQR CSV and Markdown summaries from run.jsonl.
make_prompts.pyGenerates exact-token prompt files for prompt-length sweeps.
results/Generated outputs. Ignored by default except for explicitly added final bundles.

Local Layout

The scripts assume sibling checkouts and model directories:

~/dev/grout/
~/dev/hf_models/qwen3_4b/
~/dev/hf_models/qwen3_32b/
~/dev/hf_models/qwen3_4b_f16.gguf
~/dev/bench_envs/vllm_env/
~/dev/bench_envs/sglang_env/
~/dev/bench_envs/trtllm_env/
~/dev/llama.cpp/

Override paths with MODEL_HF, GGUF_PATH, BENCH_ENVS_DIR, and LLAMA_CPP_DIR.

Build Grout

cargo build --release --features benchmarks --bin grout_bench

Engine Versions

These are the versions used for the May 2026 benchmark runs:

EngineVersion
Groutthis repository, using cuTile Rust 0.2.0
vLLM0.18.0, torch==2.10.0, flashinfer-python==0.6.6
SGLang0.5.9, torch==2.9.1, sgl-kernel==0.3.21, flashinfer-python==0.6.3
TRT-LLM1.2.0, tensorrt==10.14.1.48.post1, torch==2.9.1
llama.cppe6ec21e

Create the Python environments outside this repository, for example under ../bench_envs/. The wrappers do not install dependencies.

Benchmark Policy

  • Model: Qwen3, fp16 weights, no quantization.
  • Batch size: 1.
  • Sampling: greedy.
  • Prefix cache: disabled for every comparison engine.
  • Decode length: fixed with EOS ignored or min_tokens=tg, depending on engine.
  • Metric used for cross-engine plots: request_gen_tps = generated_tokens / e2e_ms.
  • Aggregation: median and IQR over measured reps. No outlier filtering.
  • Clocks: driver-controlled by default. Passing an MHz value to a sweep locks clocks for debugging, but paper runs should disclose whichever policy is used.

Canonical Runs

RTX 5090 / sm_120, Qwen3-4B:

./benchmarks/sweep_tg_sm120.sh
./benchmarks/sweep_pp_sm120.sh

B200 / sm_100, Qwen3-32B:

MODEL_HF=../hf_models/qwen3_32b ./benchmarks/sweep_tg_sm100.sh
MODEL_HF=../hf_models/qwen3_32b ./benchmarks/sweep_pp_sm100.sh

Smoke runs:

BENCH_REPS=1 BENCH_REPS_LONG=1 WARMUP_REPS=1 ./benchmarks/sweep_tg_sm120.sh
BENCH_REPS=1 BENCH_REPS_LONG=1 WARMUP_REPS=1 ./benchmarks/sweep_pp_sm120.sh

Run one cell:

SWEEP_TG_VALUES=8192 ./benchmarks/sweep_tg_sm120.sh
SWEEP_PP_VALUES=8192 ./benchmarks/sweep_pp_sm120.sh

Optional engines:

SWEEP_ENABLE_LLAMA=1 ./benchmarks/sweep_tg_sm120.sh
SWEEP_ENABLE_TRTLLM=1 ./benchmarks/sweep_tg_sm120.sh

TRT-LLM is only wired into the TG sweep.

Outputs

Each sweep writes:

benchmarks/results/sweep/<timestamp>/
  run.jsonl
  aggregate.csv
  aggregate.md
  summary_<timestamp>.txt

run.jsonl is the raw per-rep source of truth. aggregate.csv contains the median/IQR table used for plots. See RESULTS.md for the committed B200 result bundle.