Parameter#
Execute evalscope perf --help to get a full parameter description.
Basic Settings#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Name or path of the test model |
- |
|
|
API address, supporting |
- |
|
|
Name for wandb/swanlab database result and result database |
|
|
|
Service API type |
- |
|
|
Port for local inference service |
|
|
|
Attention implementation method |
|
|
|
API key |
|
|
|
Whether to output debug information |
|
|
|
External workload scenario. |
|
Network Configuration#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Total timeout for each request (seconds) |
|
|
|
Network connection timeout (seconds) |
|
|
|
Network read timeout (seconds) |
|
|
|
Additional HTTP headers |
- |
|
|
Do not send connection test, start stress test directly |
|
Request Control#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Number of concurrent requests |
|
|
|
Total number of requests to be sent |
|
|
|
Request scheduling rate (requests/second) |
|
|
|
Log every N queries |
|
|
|
Whether to use SSE stream output |
|
|
|
Sleep time between each performance test (seconds) |
|
|
|
Enable optional PD-disaggregation handoff metrics for streaming generation |
|
|
|
Enable open-loop mode: dispatch requests following a Poisson arrival schedule without semaphore backpressure. |
|
|
|
Number or ratio of warmup requests: |
|
|
|
Wall-clock budget for one benchmark run (seconds) |
|
Tip
Closed-loop (default) vs Open-loop (--open-loop) — parameter behaviour comparison:
Closed-loop (default) |
Open-loop ( |
|
|---|---|---|
|
Controls request scheduling rate ( |
Controls dispatch rate; must be > 0; accepts multiple values (e.g. |
|
Total requests per run; must match |
Total requests per run; must match |
|
Max in-flight requests; each worker waits for a response before sending the next (backpressure) |
Ignored; concurrency is unbounded (INF); requests are fired on schedule without waiting for responses |
Use case |
Measure latency and throughput under controlled concurrency |
Simulate realistic traffic (arrivals independent of service time); sweep throughput-latency curve across multiple rates |
SLA Settings#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Whether to enable SLA auto-tuning mode |
|
|
|
Variable for auto-tuning |
|
|
|
SLA constraint conditions |
|
|
|
Upper bound of the tuned SLA variable search range |
|
|
|
Lower bound of the tuned SLA variable search range |
|
|
|
Fixed parallel workers used when |
|
|
|
Number of runs per concurrency level (average taken) |
|
|
|
Multiplier of total requests relative to the tuned variable (concurrency or rate), i.e. |
|
See also
For details on using the SLA auto-tuning feature, see the Auto-tuning Guide.
Dataset Configuration#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Dataset mode, see Dataset Modes below |
- |
|
|
Dataset file or directory path |
- |
|
|
Data source for dataset loading: |
|
|
|
Per-dataset arguments (JSON string), validated against the schema of the selected |
- |
The keys carried by --dataset-args are documented in the sections where they apply:
Key |
Purpose |
Section |
|---|---|---|
|
Truncate real data to a fixed input length |
|
|
Long-context prefix injection for very long fixed-length inputs |
|
|
Replay behaviour for production traffic |
|
Token-length arguments |
Multi-turn datasets |
Note
--multi-turn-args is deprecated; use --dataset-args instead (the key names are unchanged). The old flag still works and is automatically merged into --dataset-args (on a key conflict, --dataset-args takes precedence).
Dataset Modes#
Text / Chat
Mode |
Description |
Supports dataset-path |
|---|---|---|
|
Automatically downloads OpenQA from ModelScope |
✓ |
|
Automatically downloads LongAlpaca-12k from ModelScope |
✓ |
|
Each line is a plain prompt, an OpenAI messages JSON array, or a complete request-body JSON object; JSON is forwarded unchanged |
✓ (Required) |
|
Randomly generates prompts based on |
✗ |
|
Custom dataset parser |
✓ |
Multimodal
Mode |
Description |
Supports dataset-path |
|---|---|---|
|
Automatically downloads Flick8k from ModelScope |
✓ (directory) |
|
Automatically downloads Kontext-Bench from ModelScope |
✓ (directory) |
|
Randomly generates both image and text inputs |
✗ |
|
Round-robins all 30 MMMU validation subjects to build real multi-image requests |
✓ (MMMU-compatible |
Embedding
Mode |
Description |
Supports dataset-path |
|---|---|---|
|
Load text data from file to evaluate Embedding model |
✓ (Required) |
|
Randomly generate queries based on |
✗ |
|
Batch send text data to evaluate Embedding model |
✓ (Required) |
|
Batch send randomly generated query data to evaluate Embedding model |
✗ |
Rerank
Mode |
Description |
Supports dataset-path |
|---|---|---|
|
Load Query-Document pairs from file to evaluate Rerank model |
✓ (Required) |
|
Randomly generate query data to evaluate Rerank model |
✗ |
Multi-turn Conversation
Must be used with --multi-turn; see Multi-turn Conversation for the parameters and the Multi-turn Benchmark Guide for details.
Mode |
Description |
Supports dataset-path |
|---|---|---|
|
Synthetic multi-turn conversations; each turn randomly generates a token sequence |
✗ |
|
Automatically downloads the Chinese ShareGPT dataset (~70k conversations) from ModelScope, preserving full multi-turn conversations |
✓ |
|
Automatically downloads the English ShareGPT dataset (~70k conversations) from ModelScope, preserving full multi-turn conversations |
✓ |
|
Uses a local JSONL file as a custom multi-turn dataset |
✓ (Required) |
Production Traffic Replay
Must be used with --open-loop; see Production Traffic Replay for the trace file format and replay arguments.
Mode |
Description |
Supports dataset-path |
|---|---|---|
|
Replays a recorded production-traffic JSONL verbatim — original timestamps, request bodies, and headers — for benchmarking against real-world load (bursty arrivals, heterogeneous requests, multi-model routing) |
✓ (Required) |
Input Construction#
Controls the content and length of the input sent to the model. Below, --xxx entries are command-line flags while bare keys are passed through the --dataset-args JSON.
Length Control#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Maximum input prompt length |
|
|
|
Minimum input prompt length |
|
To benchmark a fixed input length with real data (instead of random), use the following --dataset-args keys. Supported on openqa, longalpaca, line_by_line (plain-text lines only), and ShareGPT (share_gpt_zh / share_gpt_en). Requires --tokenizer-path.
Key |
Description |
Default |
|---|---|---|
|
Target input length in tokens. When set, every prompt is truncated to this length |
disabled |
|
What to do with prompts shorter than the target: |
|
# Truncate every input to 2048 tokens
evalscope perf \
--model qwen2.5 --url http://127.0.0.1:8000/v1/completions \
--dataset share_gpt_zh --tokenizer-path /path/to/tokenizer \
--dataset-args '{"target_input_len": 2048}'
Lengths are counted as bare content tokens, without chat-template overhead. Multi-turn datasets like ShareGPT fit/filter only the last user turn by default (same as single-turn); the whole-conversation budget (sum of all message contents, over-long dropped, short padded by the prefix) applies only when a prefix_file is configured (see Long-context Prefix Injection). JSON lines in line_by_line (messages array / full request body) do not go through length control, so combining them with these keys raises an error.
How it differs from --max/min-prompt-length:
--max/min-prompt-lengthonly filters and never changes content — samples outside the range are dropped, so you get real samples of varying lengths;target_input_lenrewrites content — it truncates every prompt to the given length, ideal for controlled fixed-length benchmarking.
To get “every prompt exactly N tokens”, you must use
target_input_len; setting--min-prompt-lengthequal to--max-prompt-lengthcannot achieve it (real data almost never has prompts of exactly N tokens, so they get filtered out). Therandomdataset is the exception — it is generated on the fly, so min=max already yields a fixed length and this arg is not needed.
Long-context Prefix Injection#
Real instruction datasets are mostly 4K-8K tokens, so setting target_input_len to 128K filters everything out in drop mode and leaves varying lengths in cap mode. prefix_file lets you point at a long text (e.g. a book or document corpus); the framework slices it to exactly target_input_len − prompt length tokens and prepends it to each short prompt, so every request’s total input hits the target length while keeping the low-entropy character of real human language (ideal for measuring prefix-cache hit rates and MTP acceptance rates). Supported on the same datasets as Length Control.
Key |
Description |
Default |
|---|---|---|
|
Path to the long prefix text file (UTF-8 plain text). Requires |
disabled |
|
Injection role for the prefix: |
|
# Align every request to exactly 131072 tokens using a long text prefix injected as the system role
evalscope perf \
--model qwen2.5 --url http://127.0.0.1:8000/v1/chat/completions \
--dataset openqa --tokenizer-path /path/to/tokenizer \
--dataset-args '{"target_input_len": 131072, "prefix_file": "/path/to/long_text.txt", "prefix_role": "system"}'
Behavior notes:
Budget split: the prompt is kept as-is (over-length prompts are truncated per
input_len_mode); the prefix is sliced to exactlytarget_input_len − tokens of all message contents, so the total equals the target. Multi-turn history counts towards the budget (see the length convention in Length Control).Incompatible with
drop:droponly keeps prompts that already filltarget_input_len, leaving a zero prefix budget, so the injection could never take effect — the combination is rejected at config time. Usecapplus prefix filling for fixed lengths.Short prefix: when the prefix file has fewer tokens than the remaining budget, it is repeated (tiled) to cover it and then truncated precisely, with a warning.
Fallback: when
apply_chat_templateis off (e.g. the/v1/completionsendpoint), a system message cannot be injected, so the prefix falls back to plain-text concatenation with a warning.Join boundary: with
prefix_role="user"and in the plain-text fallback the prefix sits directly next to the prompt. The prefix and prompt are counted independently, so when the tokenizer merges or splits characters across the join the measured total can differ from the target by about ±1 token.prefix_role="system"(chat-template mode) is separated by message markers and is always exact.Cache friendly: all requests share the same prefix head (lengths differ slightly per prompt), which naturally suits prefix-cache hit testing.
Note
The prefix_file in this section injects a real text prefix for real datasets, whereas --prefix-length injects a random token prefix and only applies to the random dataset (see Random Data Generation below). They serve different purposes and should not be confused.
Random Data Generation#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Length of the random token prefix |
|
|
|
Image width for random VL dataset |
|
|
|
Image height for random VL dataset |
|
|
|
Image format for random VL dataset |
|
|
|
Number of images for random VL dataset |
|
|
|
Patch size for the image |
|
The length of random prompts is set by --min-prompt-length / --max-prompt-length (equal values yield a fixed length); target_input_len is not needed.
Prompt and Template#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Specify request prompt |
- |
|
|
Specify query template |
- |
|
|
Whether to apply chat template |
|
|
|
Tokenize the prompt client-side into a token-ID list and send it directly via |
|
Multi-turn Conversation#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Enable multi-turn conversation benchmark mode; |
|
|
|
Minimum number of user turns per conversation; used by |
|
|
|
Maximum number of user turns per conversation; required for |
|
|
|
Worker processes for CPU-bound dataset/request generation. |
|
Token-length arguments for multi-turn datasets such as swe_smith are passed via --dataset-args.
See also
Available multi-turn datasets are listed in Dataset Modes; for full usage see the Multi-turn Benchmark Guide.
Production Traffic Replay#
Use --dataset workload_trace to replay recorded production traffic verbatim following its original arrival timing, closely matching real-world load. Requires --open-loop; no --rate is needed (arrival times come from the trace timestamps). See the full example at Production Traffic Replay.
The trace file is JSONL, one request record per line:
{"body": {"model": "qwen-plus", "messages": [{"role": "user", "content": "hi"}]}, "timestamp": 1700000000.0}
{"body": {"model": "qwen-max", "messages": [{"role": "user", "content": "hello"}]}, "timestamp": 1700000001.5, "headers": {"X-Tag": "exp"}, "request_id": "req-42", "completion_tokens": 256}
Field |
Required |
Description |
|---|---|---|
|
✓ |
Complete request body (dict or JSON string), sent as-is |
|
✓ |
Arrival time (number or ISO-8601 string); only relative deltas matter; must be monotonically non-decreasing |
|
Per-request HTTP headers (merged with CLI headers, CLI wins; hop-by-hop headers are stripped) |
|
|
Propagated to results for correlation with the original request |
|
|
Used together with |
Replay behaviour is tuned via --dataset-args:
Key |
Type |
Description |
Default |
|---|---|---|---|
|
float |
Replay speed multiplier (2.0 = 2× faster, 0.5 = 2× slower) |
|
|
str |
Replace the |
disabled |
|
dict |
Remap |
disabled |
|
bool |
Set |
|
Note
--model does not rewrite the trace body for workload_trace — each request keeps its own model, preserving multi-model routing. To rewrite models, use model_override / model_mapping.
Model and Generation#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Tokenizer weights path |
|
|
|
frequency_penalty value |
- |
|
|
Whether to return logarithmic probabilities |
- |
|
|
Maximum number of tokens that can be generated |
|
|
|
Minimum number of tokens to generate |
- |
|
|
Number of completion choices to generate |
- |
|
|
Random seed |
|
|
|
Tokens that stop the generation |
- |
|
|
IDs of tokens that stop the generation |
- |
|
|
Sampling temperature |
|
|
|
Top-p sampling |
- |
|
|
Top-k sampling |
- |
|
|
Additional parameters to be passed in the request body |
- |
Tokenizer and chat template#
When benchmarking a chat/completions endpoint, --apply-chat-template is on by default and the client applies the chat template before counting tokens, so client-side lengths line up with the usage.prompt_tokens reported by the service; the tokenizer given to --tokenizer-path must therefore ship a Jinja chat template. DeepSeek-V3.2 / V4 provide encoding scripts instead, and base / pretrain checkpoints have no template either — those fail with an error that lists the available options.
Two things to watch out for: without --tokenizer-path, --min-prompt-length / --max-prompt-length filter by characters instead of tokens; and borrowing another model’s tokenizer does not fail, but a mismatched vocabulary silently distorts token counts.
Output#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Visualizer to use |
|
|
|
Whether to enable progress tracking, writing hierarchical stress-test progress to |
|
|
|
wandb API key for logging metrics to wandb |
- |
|
|
swanlab API key for logging metrics to swanlab |
- |
|
|
Output file path |
|
|
|
Exclude timestamp from output directory name |
|
Other Parameters#
Parameter |
Type |
Description |
Default |
|---|---|---|---|
|
|
Number of rows buffered before writing results to SQLite database |
|
|
|
Maximum size of the request queue |
|
|
|
Maximum number of in-flight tasks |
|