Repository: modelscope/evalscope
Issue: EvalScope Perf 进行性能压测，相比其他压测工具性能差异显著
Root cause: Algorithmic Error

## 自查清单

在提交 issue 之前，请确保您已完成以下步骤:
- [x] 我已仔细阅读了[相关使用说明文档](https://evalscope.readthedocs.io/zh-cn/latest/get_started/parameters.html)
- [x] 我已查看了[常见问题解答](https://evalscope.readthedocs.io/zh-cn/latest/get_started/faq.html)
- [x] 我已搜索并查看了现有的 issues，确认这不是一个重复的问题

## 问题描述

目前对比了 EvalScope Perf 与 Guidellm、Genai Bench、aiperf、inference perf等压测工具，发现EvalScope Perf与其他工具相比性能差异巨大。

模型：Qwen3-8B
输入：1k
输出：128
推理框架：SGLang 0.5.6.post1
硬件：H200  x1
并发：20

<img width="1376" height="618" alt="Image" src="https://github.com/user-attachments/assets/6cb9cb46-6c7e-47b0-9faf-3eaead411d13" />


即使当并发为1时，发现差异吞吐差异仍然很大。



<img width="1302" height="334" alt="Image" src="https://github.com/user-attachments/assets/2465c89a-65e8-4059-9f56-6c51cd1a5a80" />

单并发下，通过打印日志统计：

平均端到端时延：0.7378
平均每个请求之间的间隙：0.922

通过观察SLang 日志发现，EvalScope Perf 不能够使请求饱和。而其他框架不会存在类似问题。

<img width="2324" height="1378" alt="Image" src="https://github.com/user-attachments/assets/87961948-4de3-44c5-9bf4-c1a45b48bf87" />


初步观察代码判断，目前EvalScope Perf中采用阻塞等待策略，而不是持续填充策略，导致请求流出现间隙。


## EvalScope 版本（必填）
v0.17.1

## 使用的工具
- [x] Native / 原生框架
- [ ] Opencompass backend
- [ ] VLMEvalKit backend
- [ ] RAGEval backend
- [x] Perf / 模型推理压测工具
- [ ] Arena / 竞技场模式

## 执行的代码或指令

```
evalscope perf \
  --parallel 20 \
  --number 500  \
  --model Qwen-bf16-isl1k-osl128-056post1 \
  --url http://localhost:8000/v1/chat/completions \
  --api openai \
  --dataset random \
  --max-tokens 128 \
  --min-tokens 128 \
  --prefix-length 0 \
  --min-prompt-length 1024 \
  --max-prompt-length 1024 \
  --tokenizer-path /global/models/Qwen3-8B \
  --extra-args '{"ignore_eos": true}' \
  --swanlab-api-key local \
  --outputs-dir /workspace/outputs/evalscope-perf-qwen3-8b
```


**其他压测工具脚本**：

guidellm:
```
MODEL_PATH=/global/models/Qwen3-8B/
OUTPUT_PATH=/workspace/outputs/guidellm-eval/qwen3-8b-bf16-parallel20
rm -rf $OUTPUT_PATH
mkdir -p $OUTPUT_PATH

guidellm benchmark \
--target "http://localhost:8000" \
--processor $MODEL_PATH \
--request-type text_completions \
--profile concurrent \
--rate 20 \
--max-requests 500 \
--data "prompt_tokens=1024,output_tokens=128,samples=2000" \
--output-dir $OUTPUT_PATH \
--outputs json,csv,yaml,console
```

genai-bench:

```
BASE_PATH=/workspace/outputs/genai-bench-eval
NAME=qwen3-8b-bf16-parallel20

rm -rf $BASE_PATH/$NAME

genai-bench benchmark \
--api-backend sglang \
--api-base "http://localhost:8000" \
--api-model-name "Qwen3-8B" \
--api-key "xxx" \
--model-tokenizer "/global/models/Qwen3-8B" \
--server-engine "SGLang" \
--server-gpu-type "H200" \
--server-version "v0.5.6" \
--server-gpu-count 1 \
--task text-to-text \
--max-time-per-run 10 \
--max-requests-per-run 500 \
--num-concurrency 20 \
--traffic-scenario "D(1024,128)" \
--experiment-base-dir $BASE_PATH \
--experiment-folder-name $NAME
```

aiperf:
```
aiperf profile \
--model qwen3 \
--tokenizer /global/models/Qwen3-8B \
--endpoint-type chat \
--endpoint /v1/chat/completions \
--streaming \
--url localhost:8000 \
--synthetic-input-tokens-mean 1024 \
--synthetic-input-tokens-stddev 0 \
--output-tokens-mean 128 \
--output-tokens-stddev 0 \
--extra-inputs ignore_eos:true \
--concurrency 20 \
--request-count 500 \
--warmup-request-count 0 \
--num-dataset-entries 1000 \
--random-seed 100
```




感谢你的反馈，我再测试一下

我在A100显卡，vLLM(0.11.1)和sglang(0.5.6.post2)框架上测试了一下：

*evalscope和aiperf没有出现太大的偏差，吞吐量也近似*

## vLLM启动命令：
```shell
VLLM_USE_MODELSCOPE=True CUDA_VISIBLE_DEVICES=0 \
python -m vllm.entrypoints.openai.api_server \
  --model ./Qwen2.5-7B-Instruct \
  --gpu-memory-utilization 0.8 \
  --served-model-name Qwen2.5-7B-Instruct \
  --trust-remote-code \
  --port 8801 \
  --no-enable-prefix-caching
```

## aiperf
```shell
aiperf profile \
--model Qwen2.5-7B-Instruct \
--tokenizer /mnt/data/data/user/maoyunlin.myl/models/Qwen2.5-7B-Instruct \
--endpoint-type chat \
--endpoint /v1/chat/completions \
--streaming \
--url localhost:8801 \
--synthetic-input-tokens-mean 1024 \
--synthetic-input-tokens-stddev 0 \
--output-tokens-mean 128 \
--output-tokens-stddev 0 \
--extra-inputs ignore_eos:true \
--concurrency 20 \
--request-count 500 \
--warmup-request-count 0 \
--num-dataset-entries 1000 \
--random-seed 100


                                            NVIDIA AIPerf | LLM Metrics                                            
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━┓
┃                               Metric ┃      avg ┃      min ┃      max ┃      p99 ┃      p90 ┃      p50 ┃    std ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━┩
│             Time to First Token (ms) │   293.44 │    89.05 │ 2,334.31 │ 2,089.30 │   391.95 │   208.90 │ 321.91 │
│            Time to Second Token (ms) │    96.54 │    12.20 │   181.28 │   133.77 │   132.02 │    80.56 │  35.89 │
│                 Request Latency (ms) │ 3,105.68 │ 1,914.59 │ 5,078.65 │ 4,816.03 │ 3,140.26 │ 3,074.84 │ 323.76 │
│             Inter Token Latency (ms) │    22.15 │    13.84 │    23.71 │    23.56 │    23.12 │    22.26 │   1.15 │
│     Output Token Throughput Per User │    45.31 │    42.17 │    72.26 │    60.59 │    46.91 │    44.93 │   2.97 │
│                    (tokens/sec/user) │          │          │          │          │          │          │        │
│      Output Sequence Length (tokens) │   127.99 │   126.00 │   128.00 │   128.00 │   128.00 │   128.00 │   0.12 │
│       Input Sequence Length (tokens) │ 1,024.00 │ 1,024.00 │ 1,025.00 │ 1,024.00 │ 1,024.00 │ 1,024.00 │   0.04 │
│ Output Token Throughput (tokens/sec) │   822.02 │      N/A │      N/A │      N/A │      N/A │      N/A │    N/A │
│    Request Throughput (requests/sec) │     6.42 │      N/A │      N/A │      N/A │      N/A │      N/A │    N/A │
│             Request Count (requests) │   500.00 │      N/A │      N/A │      N/A │      N/A │      N/A │    N/A │
└──────────────────────────────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴────────┘
```
## evalscope
```shell
evalscope perf \
  --parallel 20 \
  --number 500  \
  --model Qwen2.5-7B-Instruct \
  --url http://localhost:8801/v1/chat/completions \
  --api openai \
  --dataset random \
  --max-tokens 128 \
  --min-tokens 128 \
  --prefix-length 0 \
  --min-prompt-length 1024 \
  --max-prompt-length 1024 \
  --tokenizer-path /mnt/data/data/user/maoyunlin.myl/models/Qwen2.5-7B-Instruct \
  --extra-args '{"ignore_eos": true}'

  Benchmarking summary:
+-----------------------------------+-----------+
| Key                               |     Value |
+===================================+===========+
| Time taken for tests (s)          |   71.6469 |
+-----------------------------------+-----------+
| Number of concurrency             |   20      |
+-----------------------------------+-----------+
| Request rate (req/s)              |   -1      |
+-----------------------------------+-----------+
| Total requests                    |  500      |
+-----------------------------------+-----------+
| Succeed requests                  |  500      |
+-----------------------------------+-----------+
| Failed requests                   |    0      |
+-----------------------------------+-----------+
| Output token throughput (tok/s)   |  893.269  |
+-----------------------------------+-----------+
| Total token throughput (tok/s)    | 8039.42   |
+-----------------------------------+-----------+
| Request throughput (req/s)        |    6.9787 |
+-----------------------------------+-----------+
| Average latency (s)               |    2.8604 |
+-----------------------------------+-----------+
| Average time to first token (s)   |    0.3971 |
+-----------------------------------+-----------+
| Average time per output token (s) |    0.0194 |
+-----------------------------------+-----------+
| Average inter-token latency (s)   |    0.0192 |
+-----------------------------------+-----------+
| Average input tokens per request  | 1024      |
+-----------------------------------+-----------+
| Average output tokens per request |  128      |
+-----------------------------------+-----------+
2025-12-23 14:40:26 - evalscope - INFO: 
Percentile results:
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
| Percentiles | TTFT (s) | ITL (s) | TPOT (s) | Latency (s) | Input tokens | Output tokens | Output (tok/s) | Total (tok/s) |
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
|     10%     |  0.2197  | 0.0125  |  0.0188  |   2.7301    |     1024     |      128      |    41.8981     |   377.0828    |
|     25%     |  0.3336  | 0.0126  |  0.0192  |    2.827    |     1024     |      128      |    44.2821     |   398.5391    |
|     50%     |  0.3858  | 0.0127  |  0.0195  |    2.842    |     1024     |      128      |    45.0397     |    405.357    |
|     66%     |  0.3877  | 0.0128  |  0.0197  |   2.8609    |     1024     |      128      |    45.2015     |   406.8133    |
|     75%     |  0.3887  | 0.0129  |  0.0198  |   2.8906    |     1024     |      128      |     45.285     |   407.5653    |
|     80%     |   0.39   |  0.013  |  0.0199  |    2.902    |     1024     |      128      |    45.4057     |   408.6511    |
|     90%     |  0.5916  | 0.0134  |  0.0207  |   3.0566    |     1024     |      128      |    46.8974     |   422.0766    |
|     95%     |  0.8429  | 0.0833  |  0.0213  |   3.1779    |     1024     |      128      |    50.1498     |   451.3483    |
|     98%     |  1.1092  | 0.1293  |  0.0216  |   3.4323    |     1024     |      128      |    55.9005     |   503.1042    |
|     99%     |  1.2381  | 0.1298  |  0.0218  |   3.6154    |     1024     |      128      |    58.8978     |   530.0804    |
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+

```

## sglang启动命令：

```shell
 python3 -m sglang.launch_server --model-path ./Qwen2.5-7B-Instruct \
 --host 0.0.0.0 --port 8801 --served-model-name Qwen2.5-7B-Instruct --disable-radix-cache
```

## aiperf
```text
                                            NVIDIA AIPerf | LLM Metrics                                            
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━┓
┃                               Metric ┃      avg ┃      min ┃      max ┃      p99 ┃      p90 ┃      p50 ┃    std ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━┩
│             Time to First Token (ms) │   912.29 │    81.52 │ 2,270.46 │ 2,045.55 │ 1,259.84 │ 1,052.06 │ 392.14 │
│            Time to Second Token (ms) │   374.69 │    11.73 │ 1,186.79 │ 1,181.85 │   695.01 │   213.90 │ 324.90 │
│                 Request Latency (ms) │ 2,808.01 │ 2,745.55 │ 3,780.53 │ 3,780.14 │ 2,776.65 │ 2,767.19 │ 198.50 │
│             Inter Token Latency (ms) │    14.93 │    11.88 │    21.91 │    21.10 │    17.34 │    13.48 │   2.68 │
│     Output Token Throughput Per User │    69.01 │    45.65 │    84.15 │    84.13 │    84.07 │    74.17 │  11.43 │
│                    (tokens/sec/user) │          │          │          │          │          │          │        │
│      Output Sequence Length (tokens) │   127.98 │   123.00 │   129.00 │   128.00 │   128.00 │   128.00 │   0.25 │
│       Input Sequence Length (tokens) │ 1,024.00 │ 1,024.00 │ 1,025.00 │ 1,024.00 │ 1,024.00 │ 1,024.00 │   0.04 │
│ Output Token Throughput (tokens/sec) │   909.90 │      N/A │      N/A │      N/A │      N/A │      N/A │    N/A │
│    Request Throughput (requests/sec) │     7.11 │      N/A │      N/A │      N/A │      N/A │      N/A │    N/A │
│             Request Count (requests) │   500.00 │      N/A │      N/A │      N/A │      N/A │      N/A │    N/A │
└──────────────────────────────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┴────────┘
```

## evalscope
```text
Benchmarking summary:
+-----------------------------------+-----------+
| Key                               |     Value |
+===================================+===========+
| Time taken for tests (s)          |   70.6069 |
+-----------------------------------+-----------+
| Number of concurrency             |   20      |
+-----------------------------------+-----------+
| Request rate (req/s)              |   -1      |
+-----------------------------------+-----------+
| Total requests                    |  500      |
+-----------------------------------+-----------+
| Succeed requests                  |  500      |
+-----------------------------------+-----------+
| Failed requests                   |    0      |
+-----------------------------------+-----------+
| Output token throughput (tok/s)   |  906.428  |
+-----------------------------------+-----------+
| Total token throughput (tok/s)    | 8157.85   |
+-----------------------------------+-----------+
| Request throughput (req/s)        |    7.0815 |
+-----------------------------------+-----------+
| Average latency (s)               |    2.8196 |
+-----------------------------------+-----------+
| Average time to first token (s)   |    0.805  |
+-----------------------------------+-----------+
| Average time per output token (s) |    0.0159 |
+-----------------------------------+-----------+
| Average inter-token latency (s)   |    0.0157 |
+-----------------------------------+-----------+
| Average input tokens per request  | 1024      |
+-----------------------------------+-----------+
| Average output tokens per request |  128      |
+-----------------------------------+-----------+
2025-12-23 15:09:14 - evalscope - INFO: 
Percentile results:
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
| Percentiles | TTFT (s) | ITL (s) | TPOT (s) | Latency (s) | Input tokens | Output tokens | Output (tok/s) | Total (tok/s) |
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
|     10%     |  0.1518  | 0.0118  |  0.0126  |   2.7174    |     1024     |      128      |    44.8447     |   403.6026    |
|     25%     |  0.5946  |  0.012  |  0.0131  |   2.7349    |     1024     |      128      |    46.0001     |   414.0009    |
|     50%     |  0.7208  | 0.0121  |  0.0162  |   2.7597    |     1024     |      128      |    46.3844     |   417.4596    |
|     66%     |  1.067   | 0.0121  |  0.017   |   2.7747    |     1024     |      128      |    46.6432     |   419.7887    |
|     75%     |  1.0924  | 0.0122  |  0.0173  |   2.7831    |     1024     |      128      |    46.8046     |   421.2413    |
|     80%     |  1.1265  | 0.0122  |  0.0177  |   2.7856    |     1024     |      128      |    46.8482     |   421.6342    |
|     90%     |  1.1858  | 0.0124  |  0.0205  |   2.8545    |     1024     |      128      |    47.1085     |   423.9768    |
|     95%     |  1.2071  |  0.013  |  0.021   |    2.867    |     1024     |      128      |    47.3432     |   426.0885    |
|     98%     |   1.77   | 0.0241  |  0.0218  |   4.2775    |     1024     |      128      |    49.1523     |   442.3703    |
|     99%     |  1.7729  | 0.0662  |  0.0233  |    4.28     |     1024     |      128      |    49.1817     |   442.6351    |
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
```

@Yunnglin 感谢你的结果，我刚刚重新测试了下，去掉`--swanlab-api-key local`之后，性能结果基本一致。但是这样就没有办法使用swanlab离线看板可视化测试结果。
```
Benchmarking summary:
+-----------------------------------+------------+
| Key                               |      Value |
+===================================+============+
| Time taken for tests (s)          |    36.7299 |
+-----------------------------------+------------+
| Number of concurrency             |    20      |
+-----------------------------------+------------+
| Total requests                    |   500      |
+-----------------------------------+------------+
| Succeed requests                  |   500      |
+-----------------------------------+------------+
| Failed requests                   |     0      |
+-----------------------------------+------------+
| Output token throughput (tok/s)   |  1742.45   |
+-----------------------------------+------------+
| Total token throughput (tok/s)    | 15682      |
+-----------------------------------+------------+
| Request throughput (req/s)        |    13.6129 |
+-----------------------------------+------------+
| Average latency (s)               |     1.4435 |
+-----------------------------------+------------+
| Average time to first token (s)   |     0.1829 |
+-----------------------------------+------------+
| Average time per output token (s) |     0.0099 |
+-----------------------------------+------------+
| Average inter-token latency (s)   |     0.0099 |
+-----------------------------------+------------+
| Average input tokens per request  |  1024      |
+-----------------------------------+------------+
| Average output tokens per request |   128      |
+-----------------------------------+------------+
2025-12-23 08:53:20 - evalscope - INFO:
Percentile results:
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
| Percentiles | TTFT (s) | ITL (s) | TPOT (s) | Latency (s) | Input tokens | Output tokens | Output (tok/s) | Total (tok/s) |
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
|     10%     |  0.0414  | 0.0064  |  0.0084  |   1.4048    |     1024     |      128      |    85.1926     |   766.7337    |
|     25%     |  0.0422  |  0.007  |  0.0093  |   1.4154    |     1024     |      128      |    86.5126     |   778.6138    |
|     50%     |  0.1732  | 0.0072  |  0.0103  |   1.4249    |     1024     |      128      |     89.835     |   808.5148    |
|     66%     |  0.2561  | 0.0074  |  0.0107  |   1.4513    |     1024     |      128      |    90.2345     |   812.1101    |
|     75%     |  0.2761  | 0.0076  |  0.0108  |   1.4796    |     1024     |      128      |    90.4424     |   813.9814    |
|     80%     |  0.2963  | 0.0081  |  0.0108  |   1.4892    |     1024     |      128      |    90.5941     |    815.347    |
|     90%     |  0.3874  | 0.0154  |  0.0109  |   1.5027    |     1024     |      128      |    91.2311     |   821.0796    |
|     95%     |  0.4806  | 0.0235  |  0.0109  |   1.5094    |     1024     |      128      |    91.7849     |   826.0638    |
|     98%     |  0.4989  | 0.0262  |  0.0113  |    1.92     |     1024     |      128      |    111.7085    |   1005.3766   |
|     99%     |   0.53   | 0.0493  |  0.0127  |   1.9363    |     1024     |      128      |    123.4759    |   1111.2831   |
+-------------+----------+---------+----------+-------------+--------------+---------------+----------------+---------------+
```

目测，可能是swanlab保存数据耗时过长导致请求流出现间隙。


@Yunnglin 我汇总了你在A100以及我在H200上面的结果，吞吐量差异比较小了，但evalscope的TTFT和ITL的指标差异还是蛮大的，而aiperf、Guidellm、Inference Perf这三个框架之间的差异会小很多。

A100：

<img width="1706" height="432" alt="Image" src="https://github.com/user-attachments/assets/42eced5b-da75-4493-837c-74b132a2f08a" />

H200：

<img width="1852" height="762" alt="Image" src="https://github.com/user-attachments/assets/eef7242e-b02e-40fd-b6e9-2da820c906a3" />

此外，如果不能利用swanlab进行本地可视化，后续是否考虑新增输出可视化图片的功能进行多组压测结果的对比？


@liguodongiot 我看下怎么处理swanlab这些数据处理部分

你可以试一下1.4.0版本，我测试过，是否开启可视化不影响结果

@Yunnglin 你好，我这边由于网络受限不能够连接到swanlab server，只能使用本地看板模型，但1.4.0版本，使用本地看板模式(`--swanlab-api-key local`)会直接Hang住。  使用远程服务（`--visualizer swanlab`）选择不可视化结果确实不影响结果。


<img width="2132" height="670" alt="Image" src="https://github.com/user-attachments/assets/4ecf6335-bdef-4998-b8f8-fcb871d2cdda" />

此外，我前几天对比了各个框架中的计算公式，如果以下面的计算公式为标准，把所有框架的ITL对齐后，发现EvalScope和aiperf/guidellm/inference perf的TTFT和ITL差异还是挺大的。

<img width="2128" height="1160" alt="Image" src="https://github.com/user-attachments/assets/ea1d38cc-369b-41ca-8001-765bb462f69d" />


运行如下命令可以正常可视化：
```shell
evalscope perf \
  --parallel 20 \
  --number 500  \
  --model Qwen2.5-7B-Instruct \
  --url http://localhost:8801/v1/chat/completions \
  --api openai \
  --dataset random \
  --max-tokens 128 \
  --min-tokens 128 \
  --prefix-length 0 \
  --min-prompt-length 1024 \
  --max-prompt-length 1024 \
  --tokenizer-path /mnt/data/data/user/maoyunlin.myl/models/Qwen2.5-7B-Instruct \
  --extra-args '{"ignore_eos": true}' \
  --swanlab-api-key local
```

<img width="2956" height="1252" alt="Image" src="https://github.com/user-attachments/assets/b2d5f770-1552-491a-96f5-08ff9ae15b53" />

此外，EvalScope和aiperf/guidellm/inference perf的TTFT和ITL差异大的问题，是重复多次运行也是这样吗