# dsv4_h200_vllm_tp4_custom_bench

## 目的

当 vLLM 使用 **TP=4**（Tensor Parallel = 4）部署时，单张 H200 上可以同时运行 **2 个独立服务**（8 卡 / 4 = 2 服务），每个服务独占 4 张 GPU：

| 服务 | 端口 | GPU 组 |
|------|------|--------|
| 1    | 30005 | 0, 1, 2, 3   |
| 2    | 30006 | 4, 5, 6, 7   |

相比 TP=2 方案，TP=4 的每个服务拥有更大的 tensor-parallel 宽度，适合更高并发的单服务场景。本实验同样使用 **自定义压测客户端 `bench_client.py`**，通过负载均衡将请求均匀分发到 2 个服务上。

## 与 TP=2 方案的区别

| 特性 | TP=2 (4 服务) | TP=4 (2 服务) |
|------|---------------|---------------|
| 服务数量 | 4 | 2 |
| 每服务 GPU | 2 | 4 |
| 单服务吞吐 | 较低 | 较高 |
| 集群总吞吐 | 相近 | 相近 |
| 适用场景 | 低并发、低延迟 | 高并发、大 batch |

## 文件说明

| 文件 | 说明 |
|------|------|
| `bench_client.py` | 自定义异步压测客户端，支持多服务负载均衡（复用 TP=2 版本） |
| `config.env` | 实验配置（2 服务、端口 30005/30006、场景等） |
| `run_bench.sh` | 编排脚本：启动 2 个服务 → 运行压测 → 解析结果 |
| `start_server.sh` | 同时启动 2 个 vLLM TP=4 服务（每服务 4 GPU） |
| `parse_results.py` | 解析 bench_client.py 输出的 JSONL，生成 `results.json` + `report.md` |

## 快速运行

```bash
# 完整流程（自动启动 2 个服务、压测、生成报告）
bash experiments/dsv4_h200_vllm_tp4_custom_bench/run_bench.sh

# 跳过服务管理（已有 2 个服务在运行）
SKIP_MANAGE_SERVER=1 bash experiments/dsv4_h200_vllm_tp4_custom_bench/run_bench.sh

# 单独运行压测客户端（多服务，带健康检查）
python3 experiments/dsv4_h200_vllm_tp4_custom_bench/bench_client.py \
  --host 127.0.0.1 \
  --ports 30005,30006 \
  --model deepseek-v4-flash \
  --concurrency 32 --input-len 512 --output-len 256 --num-prompts 640 \
  --lb-strategy round_robin \
  --health-check-interval 5 \
  --health-max-failures 2 \
  --health-recovery-interval 10 \
  --request-max-retries 2 \
  --output-file /tmp/test.jsonl

# 单独运行压测客户端（单服务，向后兼容）
python3 experiments/dsv4_h200_vllm_tp4_custom_bench/bench_client.py \
  --host 127.0.0.1 --port 30005 \
  --model deepseek-v4-flash \
  --concurrency 8 --input-len 512 --output-len 256 --num-prompts 160 \
  --output-file /tmp/test_single.jsonl

# 解析已有结果
python3 experiments/dsv4_h200_vllm_tp4_custom_bench/parse_results.py \
  experiments/dsv4_h200_vllm_tp4_custom_bench/results/<RUN_ID>
```

## 场景设计

本实验覆盖了从 **单并发** 到 **128 并发** 的梯度，以及不同输入/输出长度组合：

| 并发 | 输入长度 | 输出长度 | 请求数 | 说明 |
|------|----------|----------|--------|------|
| 1    | 512      | 256      | 20     | 单并发基线，测纯延迟 |
| 2    | 512      | 256      | 40     | 低并发，2 服务各 1 req |
| 4    | 512      | 256      | 80     | 中低并发 |
| 8    | 512      | 256      | 160    | 中等并发 |
| 16   | 512      | 256      | 320    | 中高并发 |
| 32   | 512      | 256      | 640    | 高并发 |
| 64   | 512      | 256      | 1280   | 很高并发 |
| 128  | 512      | 256      | 2560   | 极限并发，测集群吞吐上限 |
| 1    | 2048     | 512      | 20     | 长输入基线 |
| 8    | 2048     | 512      | 160    | 长输入中并发 |
| 32   | 2048     | 512      | 640    | 长输入高并发 |
| 128  | 2048     | 512      | 2560   | 长输入极限并发 |
| 1    | 4096     | 1024     | 20     | 超长输入基线 |
| 8    | 4096     | 1024     | 160    | 超长输入中并发 |
| 32   | 4096     | 1024     | 640    | 超长输入高并发 |
| 128  | 4096     | 1024     | 2560   | 超长输入极限并发 |

## 健康检查与故障自动跳过

同 TP=2 版本，详见原 README。

## 负载均衡策略

同 TP=2 版本，支持 `round_robin`（默认）、`random`、`least_conn`。

## 输出格式

同 TP=2 版本，输出 JSONL 原始数据、`results.json` 结构化结果、`report.md` 人类可读报告。

## 单独启动/停止 2 个服务

```bash
# 启动 2 个服务
bash experiments/dsv4_h200_vllm_tp4_custom_bench/start_server.sh

# 停止（run_bench.sh 会自动停止，但也可以手动）
for port in 30005 30006; do
  pid_file="experiments/dsv4_h200_vllm_tp4_custom_bench/server_port${port}.pid"
  [[ -f "$pid_file" ]] && kill "$(cat "$pid_file")" 2>/dev/null || true
  rm -f "$pid_file"
done
pkill -9 -f "vllm serve.*DeepSeek-V4-Flash" 2>/dev/null || true
```

## 注意事项

- 2 个服务共享同一模型文件，确保 `/data/models/DeepSeek-V4-Flash` 存在且可访问。
- 每个服务占用约 4 张 GPU 的 90% 显存，确保无其他进程占用 GPU。
- TP=4 相比 TP=2 单服务延迟更低（通信更少），但服务数量减半，低并发下可能无法充分利用集群。
- 健康检查依赖 `/health` 端点，确保 vLLM 服务已启用该端点（vLLM 默认启用）。
- 如果某个服务频繁崩溃，检查 GPU 显存是否充足（OOM 是最常见原因）。
