Files

Multi-Turn LLM Benchmark

A benchmark tool for OpenAI-compatible LLM inference servers that supports multi-turn conversations with configurable prefix cache hit rates, input/output sequence lengths, and cross-session prefix sharing.

Entry Point

python -m ray.llm._internal.serve.benchmark.cli [OPTIONS]

Modes

Command Mode Description
... -s Smoke Single request health check
... --concurrency 8 ... Direct (concurrency) Closed-loop concurrency benchmark
... --request-rate 10 ... Direct (rate) Constant-QPS benchmark
... -i Interactive server Long-running server with UNIX socket control
... -i --client Interactive client Connect to server; REPL or --cmd one-shot

Quick Examples

Smoke test

python -m ray.llm._internal.serve.benchmark.cli -s \
  -u http://localhost:8000 -m my-model

Concurrency benchmark

python -m ray.llm._internal.serve.benchmark.cli \
  -u http://localhost:8000 -m meta-llama/Llama-3-8B-Instruct \
  --concurrency 8 --num-sessions 200 \
  --isl 2000 --osl 200 --hit-rate 0.85 --num-turns 5 \
  --think-time 1.0 --save-result results.json

Rate benchmark

python -m ray.llm._internal.serve.benchmark.cli \
  -u http://localhost:8000 -m meta-llama/Llama-3-8B-Instruct \
  --request-rate 10 --duration 120 \
  --isl 2000 --osl 200 --hit-rate 0.85 --num-turns 5 \
  --warm-up 10 --save-result results.json

Interactive server

python -m ray.llm._internal.serve.benchmark.cli -i \
  -u http://localhost:8000 -m meta-llama/Llama-3-8B-Instruct \
  --isl 2000 --osl 200 --hit-rate 0.85 --num-turns 5

Interactive client (REPL)

python -m ray.llm._internal.serve.benchmark.cli -i --client

Interactive client (one-shot)

python -m ray.llm._internal.serve.benchmark.cli -i --client --cmd "rate 10"
python -m ray.llm._internal.serve.benchmark.cli -i --client --cmd "status"

Workload Parameters

All workload parameters use simple mode: you specify user-facing values and the tool derives internal parameters (per-turn user tokens u and system prompt tokens s) automatically.

Parameter Flag Description
ISL --isl Average input sequence length (tokens) across all turns
OSL --osl Output tokens per turn
Hit rate --hit-rate Target prefix cache hit rate [0, 1]
Shared system prompt ratio --shared-system-prompt-ratio Fraction of system prompt shared across sessions (default: 0.0)
Num turns --num-turns Number of turns per conversation session
Think time --think-time Simulated user think-time between turns in seconds (default: 0)
First chunk threshold --first-chunk-threshold Number of SSE content chunks before recording first-chunk latency (default: 16)

The solver derives user_tokens (new user tokens per turn) and sys_tokens (total system prompt tokens) from these inputs. The print_summary() output shows the resolved per-turn token breakdown including cached vs. new tokens at each turn.

Tokenizer

By default, --tokenizer is None, which causes the tool to use the --model value as the HuggingFace tokenizer name. This works when --model is a valid HuggingFace model ID (e.g., meta-llama/Llama-3-8B-Instruct).

Provide --tokenizer explicitly when:

  • The --model value is an alias or deployment name that is not a valid HuggingFace repo (e.g., --model my-deployment --tokenizer meta-llama/Llama-3-8B-Instruct).
  • You want to use a local tokenizer path.

Warm-Up Strategies

Concurrency mode

Warm-up is automatic using entropy-based detection. The tool monitors the distribution of active turns across concurrent sessions. Once the Shannon entropy of the turn distribution reaches 50% of its theoretical maximum, the pool is considered at steady state and measurement begins. All requests dispatched before that point are discarded.

Rate mode

Warm-up is time-based via the --warm-up flag (in seconds). All requests whose dispatch time falls within the warm-up window are excluded from reported metrics. Set this to allow the server's KV cache to fill and stabilize.

Interactive mode

Warm-up is manual. The operator starts traffic with rate <qps>, waits for the system to stabilize, then explicitly starts a measurement window with start or measure <n>.

Interactive Commands

Command Description
help Show available commands
rate <qps> Set target request rate (0 to pause)
start Start open-ended measurement window
measure <n> Start measurement capturing next n completed requests
stop Stop measurement and print summary
status Show current state: QPS, inflight, completed, measured
workload [k=v ...] Show or update workload parameters (e.g., workload isl=3000 osl=300)
save [path] Save last measurement window to JSON
save-dir <path> Set default directory for saved results
quit Stop the benchmark server

JSON Result Schema

Results saved with --save-result (direct mode) contain these top-level keys:

Key Description
config Run configuration (concurrency/rate, model, etc.)
spec Resolved workload spec with per-turn token breakdown
first_chunk_threshold Number of chunks before recording first-chunk latency
benchmark Run metadata: total requests, duration, warm-up info
stats Aggregate latency statistics (avg, P50, P90, P99 for TTFT, FC, TPOT, latency)
per_turn Per-turn breakdown of count, avg ISL, and latency percentiles
raw_metrics Array of per-request metrics (session_id, turn, all latency fields, token counts)

Interactive mode saves with save produce a similar structure with a window summary instead of benchmark/stats/per_turn.

Typical Workflow

  1. Smoke test to verify connectivity:

    python -m ray.llm._internal.serve.benchmark.cli -s -u http://localhost:8000 -m my-model
    
  2. Direct benchmark for a fixed workload:

    python -m ray.llm._internal.serve.benchmark.cli \
      --concurrency 8 --num-sessions 200 \
      --isl 2000 --osl 200 --hit-rate 0.85 --num-turns 5 \
      -u http://localhost:8000 -m meta-llama/Llama-3-8B-Instruct \
      --save-result concurrency_8.json
    
  3. Interactive mode for exploratory testing:

    # Terminal 1: start server
    python -m ray.llm._internal.serve.benchmark.cli -i \
      --isl 2000 --osl 200 --hit-rate 0.85 --num-turns 5 \
      -u http://localhost:8000 -m meta-llama/Llama-3-8B-Instruct
    
    # Terminal 2: control
    python -m ray.llm._internal.serve.benchmark.cli -i --client
    benchctl> rate 5
    benchctl> measure 500
    benchctl> status
    benchctl> save results_qps5.json
    benchctl> rate 10
    benchctl> measure 500
    benchctl> save results_qps10.json
    benchctl> quit
    
  4. Sweep over multiple configurations: write an external script that loops over the CLI with different parameters. The tool does not include built-in sweep orchestration.