diff --git a/cvs/core/orchestrators/container.py b/cvs/core/orchestrators/container.py index 0d1d2026b..7f6c5c207 100644 --- a/cvs/core/orchestrators/container.py +++ b/cvs/core/orchestrators/container.py @@ -477,11 +477,16 @@ def setup_sshd(self): "chown -R root:root /root/.ssh", "bash -c 'chmod 700 /root/.ssh && chmod 600 /root/.ssh/*'", "mkdir -p /run/sshd", # Create privilege separation directory for sshd + "bash -c 'which sshd > /dev/null 2>&1 || (apt-get update -qq && apt-get install -y -q openssh-server iproute2)'", "/usr/sbin/sshd -p2224", ] + timeouts = { + "bash -c 'which sshd > /dev/null 2>&1 || (apt-get update -qq && apt-get install -y -q openssh-server iproute2)'": 120, + } + for cmd in ssh_setup_commands: - result = self.exec(cmd, timeout=10, detailed=True) + result = self.exec(cmd, timeout=timeouts.get(cmd, 10), detailed=True) # Check if command succeeded on all hosts for hostname, output in result.items(): if output['exit_code'] != 0: diff --git a/cvs/input/cluster_file/mi300x_atom_multi.json b/cvs/input/cluster_file/mi300x_atom_multi.json new file mode 100644 index 000000000..1ca3c32b2 --- /dev/null +++ b/cvs/input/cluster_file/mi300x_atom_multi.json @@ -0,0 +1,34 @@ +{ + "_comment": "2-node MI300X example for inferencex_atom multinode (M5). Replace mgmt_ip / node_dict with lab IPs. head_node_dict.mgmt_ip should match the rank-0 (master) node VPC IP used in params.master_addr.", + "orchestrator": "container", + "username": "{user-id}", + "priv_key_file": "/home/{user-id}/.ssh/id_rsa", + "head_node_dict": { + "mgmt_ip": "{head-node-ip}" + }, + "env_vars": {}, + "node_dict": { + "{head-node-ip}": { + "bmc_ip": "NA", + "vpc_ip": "{head-node-ip}" + }, + "{worker-node-ip}": { + "bmc_ip": "NA", + "vpc_ip": "{worker-node-ip}" + } + }, + "container": { + "lifetime": "per_run", + "image": "rocm/atom-dev:latest", + "name": "inferencex_atom_mi300x_multi", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G" + } + } + } +} diff --git a/cvs/input/cluster_file/mi300x_atom_single.json b/cvs/input/cluster_file/mi300x_atom_single.json index a57b158cd..f8b2cd835 100644 --- a/cvs/input/cluster_file/mi300x_atom_single.json +++ b/cvs/input/cluster_file/mi300x_atom_single.json @@ -1,5 +1,5 @@ { - "_comment": "Single-node MI300X example for inferencex_atom_single (ATOM driver). Replace mgmt_ip / node_dict with lab IPs.", + "_comment": "Single-node MI300X example for inferencex_atom (ATOM driver). Replace mgmt_ip / node_dict with lab IPs.", "orchestrator": "container", "username": "{user-id}", "priv_key_file": "/home/{user-id}/.ssh/id_rsa", diff --git a/cvs/input/cluster_file/mi355x_atom_multi.json b/cvs/input/cluster_file/mi355x_atom_multi.json new file mode 100644 index 000000000..a577addce --- /dev/null +++ b/cvs/input/cluster_file/mi355x_atom_multi.json @@ -0,0 +1,34 @@ +{ + "_comment": "2-node MI355X example for inferencex_atom multinode (M5). Replace mgmt_ip / node_dict with lab IPs. head_node_dict.mgmt_ip should match the rank-0 (master) node VPC IP used in params.master_addr.", + "orchestrator": "container", + "username": "{user-id}", + "priv_key_file": "/home/{user-id}/.ssh/id_rsa", + "head_node_dict": { + "mgmt_ip": "{head-node-ip}" + }, + "env_vars": {}, + "node_dict": { + "{head-node-ip}": { + "bmc_ip": "NA", + "vpc_ip": "{head-node-ip}" + }, + "{worker-node-ip}": { + "bmc_ip": "NA", + "vpc_ip": "{worker-node-ip}" + } + }, + "container": { + "lifetime": "per_run", + "image": "rocm/atom-dev:nightly_202606211542", + "name": "inferencex_atom_mi355x_multi", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G" + } + } + } +} diff --git a/cvs/input/cluster_file/mi355x_atom_single.json b/cvs/input/cluster_file/mi355x_atom_single.json index 0ea1e0eaf..3ca015048 100644 --- a/cvs/input/cluster_file/mi355x_atom_single.json +++ b/cvs/input/cluster_file/mi355x_atom_single.json @@ -1,5 +1,5 @@ { - "_comment": "Single-node MI355X example for inferencex_atom_single (ATOM driver). Pin image to match variant config / ATOM CI run.", + "_comment": "Single-node MI355X example for inferencex_atom (ATOM driver). Pin image to match variant config / ATOM CI run.", "orchestrator": "container", "username": "{user-id}", "priv_key_file": "/home/{user-id}/.ssh/id_rsa", diff --git a/cvs/input/config_file/inference/inferencex_atom/README.md b/cvs/input/config_file/inference/inferencex_atom/README.md new file mode 100644 index 000000000..470c64838 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/README.md @@ -0,0 +1,370 @@ +# InferenceX ATOM variants + +W1 **DeepSeek R1 FP8** on 8× GPU, ISL=OSL=1024, TP8. + +## Layout + +**In the CVS repo**, all variants live as flat sibling pairs in **this directory**: + +```text +{gpu}_inferencex-atom-single_{model}_{precision}[_{mode}]_config.json +{gpu}_inferencex-atom-single_{model}_{precision}[_{mode}]_threshold.json +``` + +**On your lab machine** (`~/input/config_file/inference/inferencex_atom/`), copy each variant into its **own subdirectory** so only one `*threshold.json` sits next to the config you pass to `--config_file`. `substitute_config` globs the config's parent directory; multiple `*threshold.json` files there raises `ValueError: multiple *threshold.json files … (ambiguous)`. + +```text +~/input/.../inferencex_atom/smoke/ # smoke config + smoke threshold only +~/input/.../inferencex_atom/perf/ # perf config + perf threshold only +``` + +Each shipped config sets `"threshold_json"` to the sibling threshold filename (resolved relative to the config directory). You may also use an absolute path (vLLM-style). + +Legacy nested layouts (`deepseek_r1_fp8_mi300x_atom_perf/`, `inferencemax/`, etc.) are **removed** from the repo tree. Use only the flat stems below. + +**Config filename example:** `mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json` + +| Variant | GPU | Notes | +|---------|-----|-------| +| `mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke` | MI300X | Quick path check (C=128, 128 prompts) | +| `mi300x_inferencex-atom-single_deepseek-r1_fp8_perf` | MI300X | W1 perf, portable min-SLO thresholds, server reuse across sweep | +| `mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf` | MI300X | **M4 vLLM parity** sibling of W1 perf (`framework: inferencex_atom_vllm_single`) | +| `mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi` | MI300X | **M4 vLLM parity** 2-node (`nnodes=2`, `PP=2`); scaling + optional `compare.vllm.*` | +| `mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi` | MI300X | W1 **2-node** scaling (`nnodes=2`, `PP=2`); enforced thresholds + scaling gate | +| `mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3` | MI300X | W1 FP8+MTP3 | +| `mi355x_inferencex-atom-single_deepseek-r1_fp8_perf` | MI355X | W1 perf (CI seeds, `enforce_thresholds: false`) | +| `mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi` | MI355X | W1 **2-node** scaling (`nnodes=2`, `PP=2`); `enforce_thresholds: false` until lab confirm | +| `mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi` | MI355X | **M4 vLLM parity** 2-node; `enforce_thresholds: false` until lab confirm | +| `mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3` | MI355X | W1 FP8+MTP3 | +| `mi300x_inferencex-atom-single_gpt-oss-120b_bf16` | MI300X | GPT-OSS uplift placeholder (`driver: vllm`, inline `serve_args`) | +| `mi355x_inferencex-atom-single_gpt-oss-120b_bf16` | MI355X | GPT-OSS uplift placeholder | + +ATOM server CLI is inline in each config under `roles.server.atom_args` (vLLM-style, same as `roles.server.serve_args` on `vllm_single`). MTP3 variants also set `params.bench_extra_args`. + +## Cluster + container naming + +Use `cvs/input/cluster_file/mi300x_atom_single.json` or `mi355x_atom_single.json` for single-node runs. For **multinode**, use `mi300x_atom_multi.json` or `mi355x_atom_multi.json` with two entries in `node_dict` and set `params.master_addr` in the variant config to the head node's VPC IP. `params.nnodes` must match the cluster host count; `test_setup_sshd` starts in-container sshd on port 2224 when `len(node_dict) > 1`. The cluster `container.name` must match the variant (`inferencex_atom_mi300x` / `inferencex_atom_mi355x` / `inferencex_atom_mi300x_multi` / `inferencex_atom_mi355x_multi` / `inferencex_atom_vllm_mi300x` / `inferencex_atom_vllm_mi300x_multi` / `inferencex_atom_vllm_mi355x_multi`); the suite deep-merges variant container settings over the cluster file. + +## Shared suite helpers (reusable by other inference suites) + +| Module | Purpose | +|--------|---------| +| `cvs/lib/inference/inference_suite_lifecycle.py` | Lifecycle stage tests, `InferenceLifecycle`, pytest HTML hooks | +| `cvs/lib/inference/inference_suite_results_table.py` | Configurable results table (`make_print_results_table`) | +| `cvs/lib/inference/unittests/fake_orch.py` | `FakeOrch` for Job parse unit tests | + +`inferencex_atom` imports these today; `vllm_single` may adopt them in a follow-up without duplicating code. + +## Pytest layout + +1. `test_launch_container` → `test_setup_sshd` → `test_model_fetch` +2. `test_inferencex_atom_inference` (per sweep cell; reuses server when `reuse_server_across_sweep: true`) +3. `test_cell_metrics` (one HTML row per **metric tier** per cell: throughput, ttft, tpot, health, record) +4. `test_print_results_table` → `test_teardown` + +W1 MI300X perf with two concurrency cells expects **~17** pytest rows (not one row per scalar metric). + +## Before the first lab run + +- On the **launcher** host after `git checkout` / `git pull`: run **`make install` first**, then **`source .cvs_venv/bin/activate`**. Do not activate `.cvs_venv` before `make install` — the Makefile manages that venv and install can fail if it is already active. + +```bash +cd ~/cvs +git fetch origin hnimrama/ix-atom-multinode +git reset --hard origin/hnimrama/ix-atom-multinode +make install +source .cvs_venv/bin/activate +``` + +- Edit `~/input/cluster_file/mi300x_atom_single.json` (or `mi355x_atom_single.json`): node IPs, `username`, `priv_key_file`, `container.image`. +- **Launcher vs GPU node:** CVS pytest runs on the launcher; `ContainerOrchestrator` SSHes to cluster nodes and runs `sudo docker` there. Local Docker on the launcher is not used. Prerequisites split by host: + + | Item | Launcher | GPU node (cluster `mgmt_ip`) | + |------|----------|------------------------------| + | `cvs run`, venv, `~/input/`, `~/cvs_results/` | Yes | No | + | `priv_key_file`, `~/.hf_token` (read locally by pytest) | Yes | No | + | `~/models` (when `model.remote: 0`) | No | Yes | + | `rocm/atom-dev` image, `sudo docker` | No | Yes | + | `~/LOGS/` (server/bench logs via volume mount) | No | Yes | + +- Preflight from the launcher: `ssh -i ~/.ssh/ @ 'sudo docker images | grep atom-dev; du -sh ~/models'` + +## Smoke (MI300X) + +One cell, 128 prompts — run this before the full perf matrix. + +```bash +cd ~/cvs +make install # after git pull only; run before activating venv +source .cvs_venv/bin/activate +mkdir -p ~/cvs_results ~/input/cluster_file + +SMOKE_DIR=~/input/config_file/inference/inferencex_atom/smoke +mkdir -p "$SMOKE_DIR" + +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json \ + --output "$SMOKE_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json" +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json \ + --output "$SMOKE_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json" +cvs copy-config mi300x_atom_single.json --output ~/input/cluster_file/mi300x_atom_single.json + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-smoke_mi300x.html +LOG=~/cvs_results/${TS}_ix-atom-smoke_mi300x.log + +cvs run inferencex_atom \ + --cluster_file ~/input/cluster_file/mi300x_atom_single.json \ + --config_file "$SMOKE_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +When `--html` is set, the **IX Run Deck** (`inferencex_atom_run_deck.html`, `.json`, +`_viewer.html`) is generated at session end and bundled into the pytest zip. +See `cvs/lib/report/README.md` for wiring other suites. Open the pytest HTML **Reports** +section for links. Render-only; does not affect gates. + +## W1 perf (MI300X) + +Two concurrency cells (C=128, C=256), 1000 prompts. Second cell reuses the ATOM server when `reuse_server_across_sweep: true`. + +```bash +cd ~/cvs +make install # after git pull only; run before activating venv +source .cvs_venv/bin/activate + +PERF_DIR=~/input/config_file/inference/inferencex_atom/perf +mkdir -p "$PERF_DIR" + +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json \ + --output "$PERF_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json \ + --output "$PERF_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json" + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-w1-perf_mi300x.html +LOG=~/cvs_results/${TS}_ix-atom-w1-perf_mi300x.log + +cvs run inferencex_atom \ + --cluster_file ~/input/cluster_file/mi300x_atom_single.json \ + --config_file "$PERF_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +## W1 perf multinode (MI300X, 2-node) + +Requires a 2-node cluster file, ATOM image with distributed serve support, and fabric env in `roles.server.env` (NCCL socket ifnames, etc.). One cell matches the single-node W1 reference (ISL=OSL=1024, C=128). + +```bash +cd ~/cvs +make install # after git pull only; run before activating venv +source .cvs_venv/bin/activate + +MULTI_DIR=~/input/config_file/inference/inferencex_atom/multi +mkdir -p "$MULTI_DIR" + +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json \ + --output "$MULTI_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json" +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json \ + --output "$MULTI_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json" +cvs copy-config mi300x_atom_multi.json --output ~/input/cluster_file/mi300x_atom_multi.json + +# Edit cluster + config: replace {head-node-ip} / {worker-node-ip} and set params.master_addr. + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-w1-perf-multi_mi300x.html +LOG=~/cvs_results/${TS}_ix-atom-w1-perf-multi_mi300x.log + +cvs run inferencex_atom \ + --cluster_file ~/input/cluster_file/mi300x_atom_multi.json \ + --config_file "$MULTI_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +## W1 perf multinode (MI355X, 2-node) + +Same sweep matrix as MI300X multinode. Thresholds are seeded from the MI355X single-node CI reference; `enforce_thresholds` stays `false` until a 2-node MI355X lab run confirms. + +```bash +cd ~/cvs +make install # after git pull only; run before activating venv +source .cvs_venv/bin/activate + +MULTI_DIR=~/input/config_file/inference/inferencex_atom/mi355x_multi +mkdir -p "$MULTI_DIR" + +cvs copy-config inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json \ + --output "$MULTI_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json" +cvs copy-config inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json \ + --output "$MULTI_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json" +cvs copy-config mi355x_atom_multi.json --output ~/input/cluster_file/mi355x_atom_multi.json + +# Edit cluster + config: replace {head-node-ip} / {worker-node-ip} and set params.master_addr. + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-w1-perf-multi_mi355x.html +LOG=~/cvs_results/${TS}_ix-atom-w1-perf-multi_mi355x.log + +cvs run inferencex_atom \ + --cluster_file ~/input/cluster_file/mi355x_atom_multi.json \ + --config_file "$MULTI_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +## W1 vLLM parity (MI300X, M4) + +Same sweep cells as ATOM W1 perf. Uses ``cvs run inferencex_atom_vllm_single`` (not legacy ``vllm_single``). Set ``container.image`` to your ROCm vLLM image. Optional ``run_card.parity_reference_json`` enables ``compare.vllm.*`` ratio gates (see ``mi300x_inferencex-atom-single_deepseek-r1_fp8_atom_reference.example.json``). + +```bash +cd ~/cvs && source .cvs_venv/bin/activate + +VLLM_DIR=~/input/config_file/inference/inferencex_atom/vllm_perf +mkdir -p "$VLLM_DIR" + +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json \ + --output "$VLLM_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json" +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_threshold.json \ + --output "$VLLM_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_threshold.json" +cvs copy-config mi300x_atom_single.json --output ~/input/cluster_file/mi300x_atom_single.json + +# After a green ATOM W1 run, copy cell metrics into a reference JSON and set +# run_card.parity_reference_json in the vLLM config. + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-vllm-parity_mi300x.html +LOG=~/cvs_results/${TS}_ix-atom-vllm-parity_mi300x.log + +cvs run inferencex_atom_vllm_single \ + --cluster_file ~/input/cluster_file/mi300x_atom_single.json \ + --config_file "$VLLM_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +## W1 vLLM parity multinode (MI300X) + +Same 15-cell sweep as ATOM `perf_multi`. Uses ``mi300x_atom_multi.json`` and vLLM pipeline parallelism across nodes (`PP=2`, `nnodes=2`). Populate ``run_card.parity_reference_json`` from a green ATOM multinode run for ``compare.vllm.*`` gates. + +```bash +cd ~/cvs && source .cvs_venv/bin/activate + +VLLM_MULTI_DIR=~/input/config_file/inference/inferencex_atom/vllm_perf_multi +mkdir -p "$VLLM_MULTI_DIR" + +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json \ + --output "$VLLM_MULTI_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json" +cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json \ + --output "$VLLM_MULTI_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json" +cvs copy-config mi300x_atom_multi.json --output ~/input/cluster_file/mi300x_atom_multi.json + +# Edit cluster + config: replace {head-node-ip} / {worker-node-ip}, set container.image and params.master_addr. + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-vllm-parity-multi_mi300x.html +LOG=~/cvs_results/${TS}_ix-atom-vllm-parity-multi_mi300x.log + +cvs run inferencex_atom_vllm_single \ + --cluster_file ~/input/cluster_file/mi300x_atom_multi.json \ + --config_file "$VLLM_MULTI_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +## W1 vLLM parity multinode (MI355X) + +Same sweep matrix as MI355X ATOM multinode. Thresholds are seeded; ``enforce_thresholds`` stays ``false`` until a 2-node MI355X lab run confirms. + +```bash +cd ~/cvs && source .cvs_venv/bin/activate + +VLLM_MULTI_DIR=~/input/config_file/inference/inferencex_atom/mi355x_vllm_multi +mkdir -p "$VLLM_MULTI_DIR" + +cvs copy-config inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json \ + --output "$VLLM_MULTI_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json" +cvs copy-config inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json \ + --output "$VLLM_MULTI_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json" +cvs copy-config mi355x_atom_multi.json --output ~/input/cluster_file/mi355x_atom_multi.json + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-vllm-parity-multi_mi355x.html +LOG=~/cvs_results/${TS}_ix-atom-vllm-parity-multi_mi355x.log + +cvs run inferencex_atom_vllm_single \ + --cluster_file ~/input/cluster_file/mi355x_atom_multi.json \ + --config_file "$VLLM_MULTI_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` + +## W1 perf (MI355X) + +Thresholds are seeded from [ROCm/ATOM run 27912164002](https://github.com/ROCm/ATOM/actions/runs/27912164002). `enforce_thresholds` stays `false` until an MI355X lab run confirms. + +```bash +cd ~/cvs +make install # after git pull only; run before activating venv +source .cvs_venv/bin/activate + +PERF_DIR=~/input/config_file/inference/inferencex_atom/mi355x_perf +mkdir -p "$PERF_DIR" + +cvs copy-config inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json \ + --output "$PERF_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" +cvs copy-config inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json \ + --output "$PERF_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json" +cvs copy-config mi355x_atom_single.json --output ~/input/cluster_file/mi355x_atom_single.json + +TS=$(date +%Y%m%d_%H%M%S) +HTML=~/cvs_results/${TS}_ix-atom-w1-perf_mi355x.html +LOG=~/cvs_results/${TS}_ix-atom-w1-perf_mi355x.log + +cvs run inferencex_atom \ + --cluster_file ~/input/cluster_file/mi355x_atom_single.json \ + --config_file "$PERF_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" \ + --html="$HTML" \ + --self-contained-html \ + --log-file="$LOG" \ + -vvv -s + +echo "HTML: $HTML" +echo "LOG: $LOG" +``` diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_atom_reference.example.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_atom_reference.example.json new file mode 100644 index 000000000..b16672939 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_atom_reference.example.json @@ -0,0 +1,11 @@ +{ + "_comment": "Example ATOM reference metrics for M4 compare.* gates. Populate client.* scalars from a green inferencex_atom run per cell_key. Multinode cells include PP= and NNODES= segments (e.g. ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16).", + "ISL=1024,OSL=1024,TP=8,CONC=128": { + "client.output_throughput": 3000, + "client.mean_ttft_ms": 400 + }, + "ISL=1024,OSL=1024,TP=8,CONC=256": { + "client.output_throughput": 5000, + "client.mean_ttft_ms": 450 + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json index 5778609cc..dea198029 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json @@ -1,7 +1,7 @@ { "_comment": "W1 DeepSeek R1 FP8+MTP3 on 8x MI300X. Recipe: dsr1-fp8-mi300x-atom-mtp3. Thresholds: plan Section 4.2.", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi300x", "enforce_thresholds": false, "threshold_json": "mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json index a7ad3014a..333e4ac15 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json @@ -1,7 +1,7 @@ { "_comment": "W1 DeepSeek R1 FP8 on 8x MI300X. Recipe: dsr1-fp8-mi300x-atom. Thresholds: portable minimum SLOs (throughput + health), not per-node calibration.", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi300x", "enforce_thresholds": true, "threshold_json": "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json new file mode 100644 index 000000000..5c63ecae0 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json @@ -0,0 +1,101 @@ +{ + "_comment": "W1 DeepSeek R1 FP8 multinode (2×8 GPU). Conc 16/64/128 per ISL/OSL shape (15 cells); runs grouped by shape for server reuse. max_model_length=4096.", + "schema_version": 1, + "framework": "inferencex_atom", + "gpu_arch": "mi300x", + "enforce_thresholds": true, + "threshold_json": "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json", + "run_card": { + "atom_image_pin": "rocm/atom-dev:latest", + "notes": "MI300X 2-node scaling reference (M5); align master_addr with cluster head VPC IP" + }, + "paths": { + "shared_fs": "/home/{user-id}", + "models_dir": "{shared_fs}/models", + "log_dir": "{shared_fs}/LOGS", + "hf_token_file": "{shared_fs}/.hf_token" + }, + "model": { + "id": "deepseek-ai/DeepSeek-R1-0528", + "remote": 0, + "precision": "fp8" + }, + "container": { + "lifetime": "per_run", + "name": "inferencex_atom_mi300x_multi", + "image": "rocm/atom-dev:latest", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G", + "volumes": [ + "/home/{user-id}:/home/{user-id}" + ], + "devices": [ + "/dev/dri", + "/dev/kfd" + ] + } + } + }, + "roles": { + "server": { + "atom_args": [ + "-tp", + "8", + "--kv_cache_dtype", + "fp8", + "--trust-remote-code" + ], + "env": { + "ATOM_DISABLE_MMAP": "true" + } + } + }, + "params": { + "driver": "atom", + "port_no": "8000", + "tensor_parallelism": "8", + "pipeline_parallel_size": "2", + "nnodes": "2", + "master_addr": "{head-node-ip}", + "master_port": "29501", + "scaling_baseline_output_throughput": "1500", + "random_range_ratio": "0.8", + "num_prompts": "1000", + "max_model_length": "4096", + "metric_percentiles": "95,99", + "reuse_server_across_sweep": "true", + "client_poll_count": "80", + "client_poll_wait_time": "60" + }, + "sweep": { + "sequence_combinations": [ + {"name": "w1_512_512", "isl": "512", "osl": "512"}, + {"name": "w1_1k_1k", "isl": "1024", "osl": "1024"}, + {"name": "w1_2k_1k", "isl": "2048", "osl": "1024"}, + {"name": "w1_1k_2k", "isl": "1024", "osl": "2048"}, + {"name": "w1_2k_2k", "isl": "2048", "osl": "2048"} + ], + "runs": [ + {"combo": "w1_512_512", "concurrency": 16}, + {"combo": "w1_512_512", "concurrency": 64}, + {"combo": "w1_512_512", "concurrency": 128}, + {"combo": "w1_1k_1k", "concurrency": 16}, + {"combo": "w1_1k_1k", "concurrency": 64}, + {"combo": "w1_1k_1k", "concurrency": 128}, + {"combo": "w1_2k_1k", "concurrency": 16}, + {"combo": "w1_2k_1k", "concurrency": 64}, + {"combo": "w1_2k_1k", "concurrency": 128}, + {"combo": "w1_1k_2k", "concurrency": 16}, + {"combo": "w1_1k_2k", "concurrency": 64}, + {"combo": "w1_1k_2k", "concurrency": 128}, + {"combo": "w1_2k_2k", "concurrency": 16}, + {"combo": "w1_2k_2k", "concurrency": 64}, + {"combo": "w1_2k_2k", "concurrency": 128} + ] + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json new file mode 100644 index 000000000..4d57a2ac7 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json @@ -0,0 +1,1593 @@ +{ + "_comment": "MI300X W1 multinode seeded thresholds (scaling.efficiency_pct min 50% floor (lab seed)). Cell key includes PP and NNODES segments.", + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json index 0abd57f8f..7755e17ef 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json @@ -1,7 +1,7 @@ { "_comment": "MI300X W1 smoke: one cell (C=128), num_prompts=128. Record-only; do not use for threshold calibration.", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi300x", "enforce_thresholds": false, "threshold_json": "mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json new file mode 100644 index 000000000..780964128 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json @@ -0,0 +1,88 @@ +{ + "_comment": "W1 DeepSeek R1 FP8 vLLM parity on 8x MI300X. Same sweep cells as mi300x_inferencex-atom-single_deepseek-r1_fp8_perf. Set container.image to your ROCm vLLM image. Optional run_card.parity_reference_json points at ATOM reference cell metrics for compare.* gates.", + "schema_version": 1, + "framework": "inferencex_atom_vllm_single", + "gpu_arch": "mi300x", + "enforce_thresholds": false, + "threshold_json": "mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_threshold.json", + "run_card": { + "vllm_image_pin": "", + "parity_reference_json": "", + "notes": "M4 vLLM parity sibling of ATOM W1 perf; calibrate thresholds independently" + }, + "paths": { + "shared_fs": "/home/{user-id}", + "models_dir": "{shared_fs}/models", + "log_dir": "{shared_fs}/LOGS", + "hf_token_file": "{shared_fs}/.hf_token" + }, + "model": { + "id": "deepseek-ai/DeepSeek-R1-0528", + "remote": 0, + "precision": "fp8" + }, + "container": { + "lifetime": "per_run", + "name": "inferencex_atom_vllm_mi300x", + "image": "", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G", + "volumes": [ + "/home/{user-id}:/home/{user-id}" + ], + "devices": [ + "/dev/dri", + "/dev/kfd" + ] + } + } + }, + "roles": { + "server": { + "serve_args": { + "trust-remote-code": true, + "kv-cache-dtype": "fp8" + }, + "env": { + "VLLM_ROCM_USE_AITER": "1", + "AMDGCN_USE_BUFFER_OPS": "0" + } + } + }, + "params": { + "driver": "vllm", + "port_no": "8000", + "tensor_parallelism": "8", + "random_range_ratio": "0.8", + "num_prompts": "1000", + "max_model_length": "4096", + "metric_percentiles": "95,99", + "reuse_server_across_sweep": "true", + "client_poll_count": "80", + "client_poll_wait_time": "60" + }, + "sweep": { + "sequence_combinations": [ + { + "name": "w1_1k_1k", + "isl": "1024", + "osl": "1024" + } + ], + "runs": [ + { + "combo": "w1_1k_1k", + "concurrency": 128 + }, + { + "combo": "w1_1k_1k", + "concurrency": 256 + } + ] + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json new file mode 100644 index 000000000..d7c6cc72a --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json @@ -0,0 +1,100 @@ +{ + "_comment": "W1 DeepSeek R1 FP8 vLLM parity multinode (2×8 GPU MI300X). Same sweep cells as mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi. Set container.image to your ROCm vLLM image. Optional run_card.parity_reference_json enables compare.* gates.", + "schema_version": 1, + "framework": "inferencex_atom_vllm_single", + "gpu_arch": "mi300x", + "enforce_thresholds": false, + "threshold_json": "mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json", + "run_card": { + "vllm_image_pin": "", + "parity_reference_json": "", + "notes": "M4 vLLM parity multinode sibling of ATOM W1 perf_multi; calibrate thresholds independently" + }, + "paths": { + "shared_fs": "/home/{user-id}", + "models_dir": "{shared_fs}/models", + "log_dir": "{shared_fs}/LOGS", + "hf_token_file": "{shared_fs}/.hf_token" + }, + "model": { + "id": "deepseek-ai/DeepSeek-R1-0528", + "remote": 0, + "precision": "fp8" + }, + "container": { + "lifetime": "per_run", + "name": "inferencex_atom_vllm_mi300x_multi", + "image": "", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G", + "volumes": [ + "/home/{user-id}:/home/{user-id}" + ], + "devices": [ + "/dev/dri", + "/dev/kfd" + ] + } + } + }, + "roles": { + "server": { + "serve_args": { + "trust-remote-code": true, + "kv-cache-dtype": "fp8" + }, + "env": { + "VLLM_ROCM_USE_AITER": "1", + "AMDGCN_USE_BUFFER_OPS": "0" + } + } + }, + "params": { + "driver": "vllm", + "port_no": "8000", + "tensor_parallelism": "8", + "pipeline_parallel_size": "2", + "nnodes": "2", + "master_addr": "{head-node-ip}", + "master_port": "29501", + "scaling_baseline_output_throughput": "1500", + "random_range_ratio": "0.8", + "num_prompts": "1000", + "max_model_length": "4096", + "metric_percentiles": "95,99", + "reuse_server_across_sweep": "true", + "client_poll_count": "80", + "client_poll_wait_time": "60" + }, + "sweep": { + "sequence_combinations": [ + {"name": "w1_512_512", "isl": "512", "osl": "512"}, + {"name": "w1_1k_1k", "isl": "1024", "osl": "1024"}, + {"name": "w1_2k_1k", "isl": "2048", "osl": "1024"}, + {"name": "w1_1k_2k", "isl": "1024", "osl": "2048"}, + {"name": "w1_2k_2k", "isl": "2048", "osl": "2048"} + ], + "runs": [ + {"combo": "w1_512_512", "concurrency": 16}, + {"combo": "w1_512_512", "concurrency": 64}, + {"combo": "w1_512_512", "concurrency": 128}, + {"combo": "w1_1k_1k", "concurrency": 16}, + {"combo": "w1_1k_1k", "concurrency": 64}, + {"combo": "w1_1k_1k", "concurrency": 128}, + {"combo": "w1_2k_1k", "concurrency": 16}, + {"combo": "w1_2k_1k", "concurrency": 64}, + {"combo": "w1_2k_1k", "concurrency": 128}, + {"combo": "w1_1k_2k", "concurrency": 16}, + {"combo": "w1_1k_2k", "concurrency": 64}, + {"combo": "w1_1k_2k", "concurrency": 128}, + {"combo": "w1_2k_2k", "concurrency": 16}, + {"combo": "w1_2k_2k", "concurrency": 64}, + {"combo": "w1_2k_2k", "concurrency": 128} + ] + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json new file mode 100644 index 000000000..d54446c34 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json @@ -0,0 +1,1713 @@ +{ + "_comment": "MI300X W1 vLLM parity multinode thresholds. Seeded from ATOM multinode scaffold; compare.* gates apply when run_card.parity_reference_json is set. Calibrate independently after lab run.", + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 1500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 188 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 94 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 3500 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 1750 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 438 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 219 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 5000 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 2500 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 625 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 313 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_threshold.json new file mode 100644 index 000000000..7bc3c619b --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_threshold.json @@ -0,0 +1,61 @@ +{ + "_comment": "MI300X W1 vLLM parity thresholds (independent calibration from ATOM). compare.* gates apply when run_card.parity_reference_json is set.", + "ISL=1024,OSL=1024,TP=8,CONC=128": { + "client.total_token_throughput": {"kind": "min_tok_s", "value": 3000}, + "client.output_throughput": {"kind": "min_tok_s", "value": 1500}, + "client.per_gpu_throughput": {"kind": "min_tok_s", "value": 375}, + "client.output_tput_per_gpu": {"kind": "min_tok_s", "value": 188}, + "client.mean_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.p90_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.mean_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.p90_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.mean_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.mean_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.p90_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.success_rate": {"kind": "min", "value": 1}, + "client.failed": {"kind": "max", "value": 0}, + "compare.vllm.output_throughput_ratio": {"kind": "min", "value": 0.85}, + "compare.vllm.mean_ttft_ms_ratio": {"kind": "max", "value": 1.1} + }, + "ISL=1024,OSL=1024,TP=8,CONC=256": { + "client.total_token_throughput": {"kind": "min_tok_s", "value": 5000}, + "client.output_throughput": {"kind": "min_tok_s", "value": 2500}, + "client.per_gpu_throughput": {"kind": "min_tok_s", "value": 625}, + "client.output_tput_per_gpu": {"kind": "min_tok_s", "value": 313}, + "client.mean_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.p90_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_ttft_ms": {"kind": "max_ms", "value": 1000000}, + "client.mean_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.p90_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_tpot_ms": {"kind": "max_ms", "value": 1000000}, + "client.mean_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_itl_ms": {"kind": "max_ms", "value": 1000000}, + "client.mean_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.median_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.p90_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.p95_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.p99_e2el_ms": {"kind": "max_ms", "value": 1000000}, + "client.success_rate": {"kind": "min", "value": 1}, + "client.failed": {"kind": "max", "value": 0}, + "compare.vllm.output_throughput_ratio": {"kind": "min", "value": 0.85}, + "compare.vllm.mean_ttft_ms_ratio": {"kind": "max", "value": 1.1} + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json index 6a7f8fa21..328bce4cb 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json @@ -1,7 +1,7 @@ { "_comment": "Single-node InferenceX ATOM (schema_version 1). Set container.image and container.name. ISL+OSL must fit params.max_model_length. Volume bind home only; ContainerOrchestrator adds /home/:/workspace.", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi300x", "enforce_thresholds": false, "threshold_json": "mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json index bfcc75110..f928116fc 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json @@ -1,7 +1,7 @@ { "_comment": "W1 DeepSeek R1 FP8+MTP3 on 8x MI355X. Recipe: dsr1-fp8-mi355x-atom-mtp3. Thresholds: plan Section 4.3.2.", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi355x", "enforce_thresholds": false, "threshold_json": "mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json index 6d2413b86..4abeccda3 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json @@ -1,7 +1,7 @@ { "_comment": "W1 DeepSeek R1 FP8 on 8x MI355X. Recipe: dsr1-fp8-mi355x-atom. Thresholds: plan Section 4.3 (ATOM run 27912164002).", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi355x", "enforce_thresholds": false, "threshold_json": "mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json new file mode 100644 index 000000000..bf170c467 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json @@ -0,0 +1,102 @@ +{ + "_comment": "W1 DeepSeek R1 FP8 multinode (2×8 GPU MI355X). Conc 16/64/128 per ISL/OSL shape (15 cells); runs grouped by shape for server reuse. max_model_length=4096.", + "schema_version": 1, + "framework": "inferencex_atom", + "gpu_arch": "mi355x", + "enforce_thresholds": false, + "threshold_json": "mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json", + "run_card": { + "upstream_run_url": "https://github.com/ROCm/ATOM/actions/runs/27912164002", + "atom_image_pin": "rocm/atom-dev:nightly_202606211542", + "notes": "MI355X 2-node scaling reference (M5); align master_addr with cluster head VPC IP. Lab re-run required before enforce_thresholds: true." + }, + "paths": { + "shared_fs": "/home/{user-id}", + "models_dir": "{shared_fs}/models", + "log_dir": "{shared_fs}/LOGS", + "hf_token_file": "{shared_fs}/.hf_token" + }, + "model": { + "id": "deepseek-ai/DeepSeek-R1-0528", + "remote": 0, + "precision": "fp8" + }, + "container": { + "lifetime": "per_run", + "name": "inferencex_atom_mi355x_multi", + "image": "rocm/atom-dev:nightly_202606211542", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G", + "volumes": [ + "/home/{user-id}:/home/{user-id}" + ], + "devices": [ + "/dev/dri", + "/dev/kfd" + ] + } + } + }, + "roles": { + "server": { + "atom_args": [ + "-tp", + "8", + "--kv_cache_dtype", + "fp8", + "--trust-remote-code" + ], + "env": { + "ATOM_DISABLE_MMAP": "true" + } + } + }, + "params": { + "driver": "atom", + "port_no": "8000", + "tensor_parallelism": "8", + "pipeline_parallel_size": "2", + "nnodes": "2", + "master_addr": "{head-node-ip}", + "master_port": "29501", + "scaling_baseline_output_throughput": "4000", + "random_range_ratio": "0.8", + "num_prompts": "1000", + "max_model_length": "4096", + "metric_percentiles": "95,99", + "reuse_server_across_sweep": "true", + "client_poll_count": "80", + "client_poll_wait_time": "60" + }, + "sweep": { + "sequence_combinations": [ + {"name": "w1_512_512", "isl": "512", "osl": "512"}, + {"name": "w1_1k_1k", "isl": "1024", "osl": "1024"}, + {"name": "w1_2k_1k", "isl": "2048", "osl": "1024"}, + {"name": "w1_1k_2k", "isl": "1024", "osl": "2048"}, + {"name": "w1_2k_2k", "isl": "2048", "osl": "2048"} + ], + "runs": [ + {"combo": "w1_512_512", "concurrency": 16}, + {"combo": "w1_512_512", "concurrency": 64}, + {"combo": "w1_512_512", "concurrency": 128}, + {"combo": "w1_1k_1k", "concurrency": 16}, + {"combo": "w1_1k_1k", "concurrency": 64}, + {"combo": "w1_1k_1k", "concurrency": 128}, + {"combo": "w1_2k_1k", "concurrency": 16}, + {"combo": "w1_2k_1k", "concurrency": 64}, + {"combo": "w1_2k_1k", "concurrency": 128}, + {"combo": "w1_1k_2k", "concurrency": 16}, + {"combo": "w1_1k_2k", "concurrency": 64}, + {"combo": "w1_1k_2k", "concurrency": 128}, + {"combo": "w1_2k_2k", "concurrency": 16}, + {"combo": "w1_2k_2k", "concurrency": 64}, + {"combo": "w1_2k_2k", "concurrency": 128} + ] + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json new file mode 100644 index 000000000..071b1ba74 --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_threshold.json @@ -0,0 +1,1593 @@ +{ + "_comment": "MI355X W1 multinode seeded thresholds (scaling.efficiency_pct min 50% floor). Throughput mins scaled from MI300X multinode scaffold \u00d7 single-node MI355X/MI300X ratio. Lab re-run required before enforce_thresholds: true.", + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + } + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json new file mode 100644 index 000000000..005177b2f --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json @@ -0,0 +1,100 @@ +{ + "_comment": "W1 DeepSeek R1 FP8 vLLM parity multinode (2×8 GPU MI355X). Same sweep cells as mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi. Set container.image to your ROCm vLLM image.", + "schema_version": 1, + "framework": "inferencex_atom_vllm_single", + "gpu_arch": "mi355x", + "enforce_thresholds": false, + "threshold_json": "mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json", + "run_card": { + "vllm_image_pin": "", + "parity_reference_json": "", + "notes": "MI355X vLLM parity multinode; align master_addr with cluster head VPC IP. Lab re-run required before enforce_thresholds: true." + }, + "paths": { + "shared_fs": "/home/{user-id}", + "models_dir": "{shared_fs}/models", + "log_dir": "{shared_fs}/LOGS", + "hf_token_file": "{shared_fs}/.hf_token" + }, + "model": { + "id": "deepseek-ai/DeepSeek-R1-0528", + "remote": 0, + "precision": "fp8" + }, + "container": { + "lifetime": "per_run", + "name": "inferencex_atom_vllm_mi355x_multi", + "image": "", + "runtime": { + "name": "docker", + "args": { + "network": "host", + "ipc": "host", + "privileged": true, + "shm_size": "128G", + "volumes": [ + "/home/{user-id}:/home/{user-id}" + ], + "devices": [ + "/dev/dri", + "/dev/kfd" + ] + } + } + }, + "roles": { + "server": { + "serve_args": { + "trust-remote-code": true, + "kv-cache-dtype": "fp8" + }, + "env": { + "VLLM_ROCM_USE_AITER": "1", + "AMDGCN_USE_BUFFER_OPS": "0" + } + } + }, + "params": { + "driver": "vllm", + "port_no": "8000", + "tensor_parallelism": "8", + "pipeline_parallel_size": "2", + "nnodes": "2", + "master_addr": "{head-node-ip}", + "master_port": "29501", + "scaling_baseline_output_throughput": "4000", + "random_range_ratio": "0.8", + "num_prompts": "1000", + "max_model_length": "4096", + "metric_percentiles": "95,99", + "reuse_server_across_sweep": "true", + "client_poll_count": "80", + "client_poll_wait_time": "60" + }, + "sweep": { + "sequence_combinations": [ + {"name": "w1_512_512", "isl": "512", "osl": "512"}, + {"name": "w1_1k_1k", "isl": "1024", "osl": "1024"}, + {"name": "w1_2k_1k", "isl": "2048", "osl": "1024"}, + {"name": "w1_1k_2k", "isl": "1024", "osl": "2048"}, + {"name": "w1_2k_2k", "isl": "2048", "osl": "2048"} + ], + "runs": [ + {"combo": "w1_512_512", "concurrency": 16}, + {"combo": "w1_512_512", "concurrency": 64}, + {"combo": "w1_512_512", "concurrency": 128}, + {"combo": "w1_1k_1k", "concurrency": 16}, + {"combo": "w1_1k_1k", "concurrency": 64}, + {"combo": "w1_1k_1k", "concurrency": 128}, + {"combo": "w1_2k_1k", "concurrency": 16}, + {"combo": "w1_2k_1k", "concurrency": 64}, + {"combo": "w1_2k_1k", "concurrency": 128}, + {"combo": "w1_1k_2k", "concurrency": 16}, + {"combo": "w1_1k_2k", "concurrency": 64}, + {"combo": "w1_1k_2k", "concurrency": 128}, + {"combo": "w1_2k_2k", "concurrency": 16}, + {"combo": "w1_2k_2k", "concurrency": 64}, + {"combo": "w1_2k_2k", "concurrency": 128} + ] + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json new file mode 100644 index 000000000..ca708966b --- /dev/null +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_threshold.json @@ -0,0 +1,1713 @@ +{ + "_comment": "MI355X W1 vLLM parity multinode thresholds. Seeded from ATOM multinode scaffold; compare.* when parity_reference_json is set. Lab re-run required before enforce_thresholds: true.", + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=1024,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=1024,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=16": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 8009.32 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 4004.66 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 1003.83 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 501.92 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=64": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 18688.41 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 9344.21 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 2338.72 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1169.36 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + }, + "ISL=2048,OSL=2048,TP=8,PP=2,NNODES=2,CONC=128": { + "client.total_token_throughput": { + "kind": "min_tok_s", + "value": 26697.73 + }, + "client.output_throughput": { + "kind": "min_tok_s", + "value": 13348.87 + }, + "client.per_gpu_throughput": { + "kind": "min_tok_s", + "value": 3337.22 + }, + "client.output_tput_per_gpu": { + "kind": "min_tok_s", + "value": 1671.28 + }, + "client.mean_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_ttft_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_tpot_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_itl_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.mean_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.median_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p90_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p95_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.p99_e2el_ms": { + "kind": "max_ms", + "value": 1000000 + }, + "client.success_rate": { + "kind": "min", + "value": 1 + }, + "client.failed": { + "kind": "max", + "value": 0 + }, + "scaling.efficiency_pct": { + "kind": "min", + "value": 50 + }, + "compare.vllm.output_throughput_ratio": { + "kind": "min", + "value": 0.85 + }, + "compare.vllm.mean_ttft_ms_ratio": { + "kind": "max", + "value": 1.1 + } + } +} diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_config.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_config.json similarity index 98% rename from cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_config.json rename to cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_config.json index 2b7537697..a0b574ef7 100644 --- a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_config.json +++ b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_config.json @@ -1,7 +1,7 @@ { "_comment": "Single-node InferenceX ATOM sample (schema_version 1). Set container.image and container.name. Verify serve_args against your InferenceX revision.", "schema_version": 1, - "framework": "inferencex_atom_single", + "framework": "inferencex_atom", "gpu_arch": "mi355x", "enforce_thresholds": false, "threshold_json": "mi355x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json", diff --git a/cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json b/cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json similarity index 100% rename from cvs/input/config_file/inference/inferencex_atom_single/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json rename to cvs/input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json diff --git a/cvs/input/config_file/inference/inferencex_atom_single/README.md b/cvs/input/config_file/inference/inferencex_atom_single/README.md deleted file mode 100644 index 63915906e..000000000 --- a/cvs/input/config_file/inference/inferencex_atom_single/README.md +++ /dev/null @@ -1,177 +0,0 @@ -# InferenceX ATOM single-node variants - -W1 **DeepSeek R1 FP8** on 8× GPU, ISL=OSL=1024, TP8. - -## Layout - -**In the CVS repo**, all variants live as flat sibling pairs in **this directory**: - -```text -{gpu}_inferencex-atom-single_{model}_{precision}[_{mode}]_config.json -{gpu}_inferencex-atom-single_{model}_{precision}[_{mode}]_threshold.json -``` - -**On your lab machine** (`~/input/config_file/inference/inferencex_atom_single/`), copy each variant into its **own subdirectory** so only one `*threshold.json` sits next to the config you pass to `--config_file`. `substitute_config` globs the config's parent directory; multiple `*threshold.json` files there raises `ValueError: multiple *threshold.json files … (ambiguous)`. - -```text -~/input/.../inferencex_atom_single/smoke/ # smoke config + smoke threshold only -~/input/.../inferencex_atom_single/perf/ # perf config + perf threshold only -``` - -Each shipped config sets `"threshold_json"` to the sibling threshold filename (resolved relative to the config directory). You may also use an absolute path (vLLM-style). - -Legacy nested layouts (`deepseek_r1_fp8_mi300x_atom_perf/`, `inferencemax/`, etc.) are **removed** from the repo tree. Use only the flat stems below. - -**Config filename example:** `mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json` - -| Variant | GPU | Notes | -|---------|-----|-------| -| `mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke` | MI300X | Quick path check (C=128, 128 prompts) | -| `mi300x_inferencex-atom-single_deepseek-r1_fp8_perf` | MI300X | W1 perf, portable min-SLO thresholds, server reuse across sweep | -| `mi300x_inferencex-atom-single_deepseek-r1_fp8_mtp3` | MI300X | W1 FP8+MTP3 | -| `mi355x_inferencex-atom-single_deepseek-r1_fp8_perf` | MI355X | W1 perf (CI seeds, `enforce_thresholds: false`) | -| `mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3` | MI355X | W1 FP8+MTP3 | -| `mi300x_inferencex-atom-single_gpt-oss-120b_bf16` | MI300X | GPT-OSS uplift placeholder (`driver: vllm`, inline `serve_args`) | -| `mi355x_inferencex-atom-single_gpt-oss-120b_bf16` | MI355X | GPT-OSS uplift placeholder | - -ATOM server CLI is inline in each config under `roles.server.atom_args` (vLLM-style, same as `roles.server.serve_args` on `vllm_single`). MTP3 variants also set `params.bench_extra_args`. - -## Cluster + container naming - -Use `cvs/input/cluster_file/mi300x_atom_single.json` or `mi355x_atom_single.json`. The cluster `container.name` must match the variant (`inferencex_atom_mi300x` / `inferencex_atom_mi355x`); the suite deep-merges variant container settings over the cluster file. - -## Shared suite helpers (reusable by other inference suites) - -| Module | Purpose | -|--------|---------| -| `cvs/lib/inference/inference_suite_lifecycle.py` | Lifecycle stage tests, `InferenceLifecycle`, pytest HTML hooks | -| `cvs/lib/inference/inference_suite_results_table.py` | Configurable results table (`make_print_results_table`) | -| `cvs/lib/inference/unittests/fake_orch.py` | `FakeOrch` for Job parse unit tests | - -`inferencex_atom_single` imports these today; `vllm_single` may adopt them in a follow-up without duplicating code. - -## Pytest layout - -1. `test_launch_container` → `test_setup_sshd` → `test_model_fetch` -2. `test_inferencex_atom_inference` (per sweep cell; reuses server when `reuse_server_across_sweep: true`) -3. `test_cell_metrics` (one HTML row per **metric tier** per cell: throughput, ttft, tpot, health, record) -4. `test_print_results_table` → `test_teardown` - -W1 MI300X perf with two concurrency cells expects **~17** pytest rows (not one row per scalar metric). - -## Before the first lab run - -- `git checkout` the branch under test, then `make install` and `source .cvs_venv/bin/activate` on the **launcher** host. -- Edit `~/input/cluster_file/mi300x_atom_single.json` (or `mi355x_atom_single.json`): node IPs, `username`, `priv_key_file`, `container.image`. -- **Launcher vs GPU node:** CVS pytest runs on the launcher; `ContainerOrchestrator` SSHes to cluster nodes and runs `sudo docker` there. Local Docker on the launcher is not used. Prerequisites split by host: - - | Item | Launcher | GPU node (cluster `mgmt_ip`) | - |------|----------|------------------------------| - | `cvs run`, venv, `~/input/`, `~/cvs_results/` | Yes | No | - | `priv_key_file`, `~/.hf_token` (read locally by pytest) | Yes | No | - | `~/models` (when `model.remote: 0`) | No | Yes | - | `rocm/atom-dev` image, `sudo docker` | No | Yes | - | `~/LOGS/` (server/bench logs via volume mount) | No | Yes | - -- Preflight from the launcher: `ssh -i ~/.ssh/ @ 'sudo docker images | grep atom-dev; du -sh ~/models'` - -## Smoke (MI300X) - -One cell, 128 prompts — run this before the full perf matrix. - -```bash -cd ~/cvs && source .cvs_venv/bin/activate -mkdir -p ~/cvs_results ~/input/cluster_file - -SMOKE_DIR=~/input/config_file/inference/inferencex_atom_single/smoke -mkdir -p "$SMOKE_DIR" - -cvs copy-config inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json \ - --output "$SMOKE_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json" -cvs copy-config inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json \ - --output "$SMOKE_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_threshold.json" -cvs copy-config mi300x_atom_single.json --output ~/input/cluster_file/mi300x_atom_single.json - -TS=$(date +%Y%m%d_%H%M%S) -HTML=~/cvs_results/${TS}_ix-atom-smoke_mi300x.html -LOG=~/cvs_results/${TS}_ix-atom-smoke_mi300x.log - -cvs run inferencex_atom_single \ - --cluster_file ~/input/cluster_file/mi300x_atom_single.json \ - --config_file "$SMOKE_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json" \ - --html="$HTML" \ - --self-contained-html \ - --log-file="$LOG" \ - -vvv -s - -echo "HTML: $HTML" -echo "LOG: $LOG" -``` - -When `--html` is set, the **IX Run Deck** (`inferencex_atom_run_deck.html`, `.json`, -`_viewer.html`) is generated at session end and bundled into the pytest zip. -See `cvs/lib/report/README.md` for wiring other suites. Open the pytest HTML **Reports** -section for links. Render-only; does not affect gates. - -## W1 perf (MI300X) - -Two concurrency cells (C=128, C=256), 1000 prompts. Second cell reuses the ATOM server when `reuse_server_across_sweep: true`. - -```bash -cd ~/cvs && source .cvs_venv/bin/activate - -PERF_DIR=~/input/config_file/inference/inferencex_atom_single/perf -mkdir -p "$PERF_DIR" - -cvs copy-config inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json \ - --output "$PERF_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" -cvs copy-config inference/inferencex_atom_single/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json \ - --output "$PERF_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json" - -TS=$(date +%Y%m%d_%H%M%S) -HTML=~/cvs_results/${TS}_ix-atom-w1-perf_mi300x.html -LOG=~/cvs_results/${TS}_ix-atom-w1-perf_mi300x.log - -cvs run inferencex_atom_single \ - --cluster_file ~/input/cluster_file/mi300x_atom_single.json \ - --config_file "$PERF_DIR/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" \ - --html="$HTML" \ - --self-contained-html \ - --log-file="$LOG" \ - -vvv -s - -echo "HTML: $HTML" -echo "LOG: $LOG" -``` - -## W1 perf (MI355X) - -Thresholds are seeded from [ROCm/ATOM run 27912164002](https://github.com/ROCm/ATOM/actions/runs/27912164002). `enforce_thresholds` stays `false` until an MI355X lab run confirms. - -```bash -cd ~/cvs && source .cvs_venv/bin/activate - -PERF_DIR=~/input/config_file/inference/inferencex_atom_single/mi355x_perf -mkdir -p "$PERF_DIR" - -cvs copy-config inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json \ - --output "$PERF_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" -cvs copy-config inference/inferencex_atom_single/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json \ - --output "$PERF_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json" -cvs copy-config mi355x_atom_single.json --output ~/input/cluster_file/mi355x_atom_single.json - -TS=$(date +%Y%m%d_%H%M%S) -HTML=~/cvs_results/${TS}_ix-atom-w1-perf_mi355x.html -LOG=~/cvs_results/${TS}_ix-atom-w1-perf_mi355x.log - -cvs run inferencex_atom_single \ - --cluster_file ~/input/cluster_file/mi355x_atom_single.json \ - --config_file "$PERF_DIR/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" \ - --html="$HTML" \ - --self-contained-html \ - --log-file="$LOG" \ - -vvv -s - -echo "HTML: $HTML" -echo "LOG: $LOG" -``` diff --git a/cvs/lib/inference/ADDING_A_SUITE.md b/cvs/lib/inference/ADDING_A_SUITE.md index f1ab5327a..94e90a35c 100644 --- a/cvs/lib/inference/ADDING_A_SUITE.md +++ b/cvs/lib/inference/ADDING_A_SUITE.md @@ -593,7 +593,7 @@ auto-loads it when the stem matches `cvs run …` and writes HTML/JSON/viewer at end when `--html` is set. Reports are render-only and do not change pass/fail. Do **not** wire reports in suite `conftest.py`. **IX-atom reference:** -`presets/inferencex_atom_single.py` + `presets/inferencex_atom.py`. +`presets/inferencex_atom.py` + `presets/inferencex_atom.py`. --- diff --git a/cvs/lib/inference/inference_suite_lifecycle.py b/cvs/lib/inference/inference_suite_lifecycle.py index 6d2135426..1aeee3084 100644 --- a/cvs/lib/inference/inference_suite_lifecycle.py +++ b/cvs/lib/inference/inference_suite_lifecycle.py @@ -4,7 +4,7 @@ Reusable **lifecycle-as-tests** helpers for DTNI inference suites. -``inferencex_atom_single`` imports the stage tests from here today; other suites +``inferencex_atom`` imports the stage tests from here today; other suites (``vllm_single``, future IX parity frameworks) can reuse the same module instead of copying launch / sshd / model-fetch / teardown blocks. @@ -46,6 +46,7 @@ pytest_html = None from cvs.lib import globals +from cvs.lib.inference.cache_probe import du_bytes log = globals.log @@ -78,9 +79,6 @@ def sweep_cell_result_key(variant_config, seq_combo, isl, osl, concurrency): ) -from cvs.lib.inference.cache_probe import du_bytes - - def test_launch_container(orch, variant_config, lifecycle, request): """Stage 1: launch the container.""" t = time.monotonic() @@ -106,7 +104,11 @@ def test_setup_sshd(orch, lifecycle, request): lifecycle.failed = True pytest.fail("setup_sshd() returned False") if len(orch.hosts) > 1: - probe = orch.exec("bash -c 'ss -ltn 2>/dev/null | grep -q :2224 && echo OK || echo NO'") + probe = orch.exec( + "bash -c '" + "(ss -ltn 2>/dev/null || netstat -lnt 2>/dev/null) | grep -q :2224 && echo OK || " + "(pgrep -f \"sshd.*2224\" >/dev/null && echo OK) || echo NO'" + ) if not any("OK" in (v or "") for v in (probe or {}).values()): lifecycle.failed = True pytest.fail("sshd not listening on 2224 after setup_sshd()") @@ -194,10 +196,7 @@ def attach_lifecycle_html_table(item, report): return if pytest_html is None: return - body = "".join( - f"{label}{value:.1f}{unit}" - for label, value, unit in rows - ) + body = "".join(f"{label}{value:.1f}{unit}" for label, value, unit in rows) html = f"{body}
stagevalueunit
" extras = getattr(report, "extras", []) extras.append(pytest_html.extras.html(html)) @@ -210,7 +209,7 @@ def html_metric_table_header(cells): def html_metric_table_row(report, cells): - props = dict(report.user_properties) + props = dict(getattr(report, "user_properties", ())) has = "metric_value" in props val = props.get("metric_value") unit = props.get("metric_unit", "") if has else "" diff --git a/cvs/lib/inference/inference_suite_results_table.py b/cvs/lib/inference/inference_suite_results_table.py index b98049694..39adf0f2f 100644 --- a/cvs/lib/inference/inference_suite_results_table.py +++ b/cvs/lib/inference/inference_suite_results_table.py @@ -36,6 +36,7 @@ ("Mean TTFT (ms)", "client.mean_ttft_ms"), ("Mean TPOT (ms)", "client.mean_tpot_ms"), ("P99 ITL (ms)", "client.p99_itl_ms"), + ("Scaling eff. (%)", "scaling.efficiency_pct"), ) # Optional preset for suites that want vLLM-style columns (not wired in vllm_single yet). diff --git a/cvs/lib/inference/inferencex_atom_orch.py b/cvs/lib/inference/inferencex_atom_orch.py index 234adcdad..8bc8382f2 100644 --- a/cvs/lib/inference/inferencex_atom_orch.py +++ b/cvs/lib/inference/inferencex_atom_orch.py @@ -2,13 +2,22 @@ Copyright 2025 Advanced Micro Devices, Inc. All rights reserved. -Standalone InferenceX ATOM single-node job driven by a ContainerOrchestrator. +InferenceX ATOM job driven by a ContainerOrchestrator (single- or multi-node). ``params.driver=atom`` (target): ``atom.entrypoints.openai_server`` + ``atom.benchmarks.benchmark_serving`` with ATOM JSON artifacts. ``params.driver=vllm`` (interim uplift): ``vllm serve`` + ``vllm bench serve``. +When ``params.nnodes`` > 1 the job launches one ATOM server per cluster host. +For ``driver=atom``, multinode uses ATOM SPMD data-parallel env vars +(``ATOM_DP_*``) plus ``-dp N`` when each node has enough GPUs for local DP +replicas (``tensor_parallelism * nnodes <= 8``). With TP8 across two 8-GPU +nodes, each host runs an independent ``-tp 8`` replica (no ``-dp``) because +ATOM cannot place two local DP ranks when TP already consumes all eight GPUs; +the benchmark client still runs on the head node only. For ``driver=vllm``, +multinode keeps vLLM's ``--node-rank`` / ``--master-addr`` flags. + Does NOT subclass :class:`cvs.lib.inference.base.InferenceBaseJob`. ''' @@ -26,7 +35,7 @@ class InferenceXAtomJob: - """Single-node InferenceX ATOM benchmark job driven by an injected ContainerOrchestrator.""" + """InferenceX ATOM benchmark job driven by an injected ContainerOrchestrator.""" READINESS_RE = re.compile(r"Application startup complete|Uvicorn running|Started server", re.I) COMPLETION_RE = re.compile(r"Serving Benchmark Result", re.I) @@ -37,7 +46,10 @@ class InferenceXAtomJob: re.I, ) EARLY_FAILURE_RE = re.compile( - r"no such file or directory|command not found|cannot access|failed to start", + r"no such file or directory|command not found|cannot access|failed to start" + r"|Free memory on device.*less than desired" + r"|Engine core initialization failed" + r"|WorkerProc failed to start", re.I, ) @@ -46,6 +58,18 @@ class InferenceXAtomJob: "no-enable-prefix-caching": True, } + # vLLM multinode flags; ATOM openai_server rejects these (use ATOM_DP_* / -dp instead). + _VLLM_DISTRIBUTED_FLAGS = frozenset( + { + "--node-rank", + "--master-addr", + "--master-port", + "--nnodes", + "--pipeline-parallel-size", + "--distributed-executor-backend", + } + ) + def __init__( self, orch, @@ -75,8 +99,14 @@ def __init__( self.log_subdir = log_subdir p = variant.params - self.driver = p.driver + self.driver = str(p.driver or "atom").strip().lower() self.tp = p.tensor_parallelism + self.pp = p.pipeline_parallel_size + self.nnodes = int(p.nnodes) + self.distributed = self.nnodes > 1 + raw_master = (p.master_addr or "").strip() + self.master_addr = raw_master or (orch.hosts[0] if getattr(orch, "hosts", None) else "localhost") + self.master_port = p.master_port self.port_no = p.port_no self.random_range_ratio = p.random_range_ratio self.random_prefix_len = p.random_prefix_len @@ -92,6 +122,8 @@ def __init__( self.max_model_length = str(p.max_model_length) self.bench_extra_args = (p.bench_extra_args or "").strip() self.result_stem = (p.result_filename or "results").removesuffix(".json") + raw_baseline = (p.scaling_baseline_output_throughput or "").strip() + self._scaling_baseline = float(raw_baseline) if raw_baseline else None self.model_id = variant.model.id self.log_dir = variant.paths.log_dir @@ -100,20 +132,11 @@ def __init__( self.atom_server_args = list(variant.roles.server.atom_args) self.server_env = dict(variant.roles.server.env) - self.out_dir = ( - f"{self.log_dir}/{self.log_subdir}/out-node0/" - f"isl{self.isl}_osl{self.osl}_conc{self.concurrency}" - ) - self.server_log = ( - f"{self.out_dir}/atom_server.log" - if self.driver == "atom" - else f"{self.out_dir}/vllm_serve_server.log" - ) + self.out_dir = self._node_out_dir(0) + self.server_log = self._rank_server_log(0) self.client_log = f"{self.out_dir}/client.log" self._result_artifact = ( - f"{self.out_dir}/{self.result_stem}.json" - if self.driver == "atom" - else f"{self.out_dir}/{self.result_stem}" + f"{self.out_dir}/{self.result_stem}.json" if self.driver == "atom" else f"{self.out_dir}/{self.result_stem}" ) self._precheck_wait = server_precheck_wait_s @@ -159,9 +182,29 @@ def _int_attr(name, default): kw.update(overrides) return cls(**kw) + def _node_out_dir(self, rank): + return f"{self.log_dir}/{self.log_subdir}/out-node{rank}/isl{self.isl}_osl{self.osl}_conc{self.concurrency}" + + def _rank_server_log(self, rank): + base = self._node_out_dir(rank) + name = "atom_server.log" if self.driver == "atom" else "vllm_serve_server.log" + return f"{base}/{name}" + + def _exec_all(self, cmd, **kwargs): + return self.orch.exec(cmd, **kwargs) + + def _exec_head(self, cmd, **kwargs): + if self.distributed: + return self.orch.exec_on_head(cmd, **kwargs) + return self.orch.exec(cmd, **kwargs) + def prepare_cell_out_dir(self): """Create per-cell output directory without touching server env or cache.""" - self.orch.exec(f"mkdir -p {shlex.quote(self.out_dir)}") + if self.distributed: + for rank in range(self.nnodes): + self._exec_all(f"mkdir -p {shlex.quote(self._node_out_dir(rank))}") + else: + self._exec_all(f"mkdir -p {shlex.quote(self.out_dir)}") @classmethod def _merged_serve_args(cls, variant): @@ -189,6 +232,72 @@ def _flatten_serve_args(mapping): argv.extend([opt, str(value)]) return argv + @staticmethod + def _argv_has_flag(argv, *names): + for tok in argv: + if tok in names: + return True + return False + + def _without_vllm_distributed_flags(self, argv): + """Strip vLLM multinode tokens from ``roles.server.atom_args`` if present.""" + out = [] + skip_next = False + for tok in argv: + if skip_next: + skip_next = False + continue + if tok in self._VLLM_DISTRIBUTED_FLAGS: + skip_next = True + continue + out.append(tok) + return out + + def _atom_spmd_dp_cli(self): + """Return ``-dp N`` argv when local GPUs can host *N* TP shards on one node.""" + if self.driver != "atom" or not self.distributed: + return [] + tp = int(self.tp) + if tp * self.nnodes > 8: + return [] + atom_argv = self._without_vllm_distributed_flags(self.atom_server_args) + if self._argv_has_flag(atom_argv, "-dp", "--data-parallel-size"): + return [] + return ["-dp", str(self.nnodes)] + + def _atom_multinode_argv(self): + """ATOM-only multinode CLI tokens (never vLLM ``--node-rank`` / ``--pipeline-parallel-size``).""" + return self._atom_spmd_dp_cli() + + def _atom_spmd_env_exports(self, rank): + if self.driver != "atom" or not self.distributed or not self._atom_spmd_dp_cli(): + return [] + return [ + f"export ATOM_DP_RANK={rank}", + f"export ATOM_DP_SIZE={self.nnodes}", + "export ATOM_DP_RANK_LOCAL=0", + f"export ATOM_DP_MASTER_IP={shlex.quote(self.master_addr)}", + f"export ATOM_DP_MASTER_PORT={self.master_port}", + ] + + def _vllm_distributed_argv(self, rank): + if not self.distributed: + return [] + return [ + "--node-rank", + str(rank), + "--master-addr", + str(self.master_addr), + "--master-port", + str(self.master_port), + "--nnodes", + str(self.nnodes), + "--pipeline-parallel-size", + str(self.pp), + "--distributed-executor-backend", + "mp", + ] + def build_server_cmd(self, *, clear_atom_cache=True): env_lines = [ f"export HF_TOKEN={shlex.quote(self.hf_token)}", @@ -207,12 +316,16 @@ def build_server_cmd(self, *, clear_atom_cache=True): continue env_lines.append(f"export {k}={shlex.quote(str(v))}") env_script = "\n".join(env_lines) + "\n" - self.orch.exec("bash -c " + shlex.quote(f"printf '%s' {shlex.quote(env_script)} > /tmp/server_env_script.sh")) - self.orch.exec(f"mkdir -p {shlex.quote(self.out_dir)}") + self._exec_all("bash -c " + shlex.quote(f"printf '%s' {shlex.quote(env_script)} > /tmp/server_env_script.sh")) + if self.distributed: + for rank in range(self.nnodes): + self._exec_all(f"mkdir -p {shlex.quote(self._node_out_dir(rank))}") + else: + self._exec_all(f"mkdir -p {shlex.quote(self.out_dir)}") if self.driver == "atom" and clear_atom_cache: - self.orch.exec("bash -c 'rm -rf ~/.cache/atom/* 2>/dev/null || true'") + self._exec_all("bash -c 'rm -rf ~/.cache/atom/* 2>/dev/null || true'") - def _server_argv(self): + def _server_argv(self, rank=0): argv = [ "vllm", "serve", @@ -226,10 +339,11 @@ def _server_argv(self): "--port", str(self.port_no), ] + argv.extend(self._vllm_distributed_argv(rank)) argv.extend(self._flatten_serve_args(self.serve_args)) return argv - def _atom_server_argv(self): + def _atom_server_argv(self, rank=0): argv = [ "python", "-m", @@ -239,29 +353,48 @@ def _atom_server_argv(self): "--server-port", str(self.port_no), ] - argv.extend(self.atom_server_args) + argv.extend(self._without_vllm_distributed_flags(self.atom_server_args)) + argv.extend(self._atom_multinode_argv()) return argv def start_server(self): - if self.driver == "atom": - serve_cmd = " ".join(shlex.quote(str(a)) for a in self._atom_server_argv()) - else: - serve_cmd = " ".join(shlex.quote(str(a)) for a in self._server_argv()) - inner = ( - f"source /tmp/server_env_script.sh && " - f"nohup {serve_cmd} > {shlex.quote(self.server_log)} 2>&1 &" - ) - out = self.orch.exec("bash -c " + shlex.quote(inner)) + hosts = list(getattr(self.orch, "hosts", []) or ["node0"]) + if self.distributed and len(hosts) != self.nnodes: + raise RuntimeError( + f"params.nnodes={self.nnodes} but cluster has {len(hosts)} host(s); " + "align cluster node_dict with params.nnodes" + ) label = "atom" if self.driver == "atom" else "vllm" - for host, output in out.items(): - if self.EARLY_FAILURE_RE.search(output or ""): - raise RuntimeError(f"{label} server failed to launch on {host}: {output[-500:]}") + launch_hosts = enumerate(hosts) if self.distributed else [(0, hosts[0])] + for rank, host in launch_hosts: + if self.driver == "atom": + argv = self._atom_server_argv(rank) + elif self.driver == "vllm": + argv = self._server_argv(rank) + else: + raise RuntimeError(f"unsupported params.driver={self.driver!r}; expected 'atom' or 'vllm'") + serve_cmd = " ".join(shlex.quote(str(a)) for a in argv) + rank_log = self._rank_server_log(rank) + rank_env = " && ".join(self._atom_spmd_env_exports(rank)) + env_prefix = f"{rank_env} && " if rank_env else "" + inner = ( + f"source /tmp/server_env_script.sh && {env_prefix}nohup {serve_cmd} > {shlex.quote(rank_log)} 2>&1 &" + ) + if self.distributed: + out = self._exec_all("bash -c " + shlex.quote(inner), hosts=[host]) + else: + out = self._exec_all("bash -c " + shlex.quote(inner)) + for h, output in out.items(): + if self.EARLY_FAILURE_RE.search(output or ""): + raise RuntimeError(f"{label} server failed to launch on {h} (rank {rank}): {output[-500:]}") def _atom_health_ok(self): url = f"http://localhost:{self.port_no}/health" - out = self.orch.exec( - f"curl -sf {shlex.quote(url)} -o /dev/null && echo OK || echo NO" - ) + probe = f"curl -sf {shlex.quote(url)} -o /dev/null && echo OK || echo NO" + if self.distributed: + out = self._exec_all("bash -c " + shlex.quote(probe)) + else: + out = self._exec_head("bash -c " + shlex.quote(probe)) return bool(out) and all("OK" in (v or "") for v in out.values()) def _atom_warmup_ok(self): @@ -274,24 +407,46 @@ def _atom_warmup_ok(self): f"curl -sf {shlex.quote(url)} -H 'Content-Type: application/json' " f"-d {shlex.quote(payload)} -o /dev/null --max-time 120 && echo OK || echo NO" ) - out = self.orch.exec("bash -c " + shlex.quote(inner)) + out = self._exec_head("bash -c " + shlex.quote(inner)) return bool(out) and all("OK" in (v or "") for v in out.values()) def is_ready(self): if self.driver == "atom": return self._atom_health_ok() + if self.distributed: + pattern = self.READINESS_RE.pattern + ready = True + for rank in range(self.nnodes): + log_path = self._rank_server_log(rank) + out = self._exec_all( + f"grep -qiE {shlex.quote(pattern)} {shlex.quote(log_path)}", + detailed=True, + ) + if not out or not all(r["exit_code"] == 0 for r in out.values()): + ready = False + break + return ready pattern = self.READINESS_RE.pattern - out = self.orch.exec( + out = self._exec_all( f"grep -qiE {shlex.quote(pattern)} {shlex.quote(self.server_log)}", detailed=True, ) return bool(out) and all(r["exit_code"] == 0 for r in out.values()) + def _tail_server_logs(self, lines=30): + if self.distributed: + out = {} + for rank in range(self.nnodes): + chunk = self._exec_all(f"tail -{lines} {shlex.quote(self._rank_server_log(rank))}") + out.update(chunk or {}) + return out + return self._exec_all(f"tail -{lines} {shlex.quote(self.server_log)}") + def wait_ready(self): log.info("waiting %ds for server log to materialise", self._precheck_wait) time.sleep(self._precheck_wait) - out = self.orch.exec(f"tail -30 {shlex.quote(self.server_log)}") + out = self._tail_server_logs(30) for host, output in out.items(): if self.EARLY_FAILURE_RE.search(output or ""): label = "atom" if self.driver == "atom" else "vllm" @@ -303,12 +458,10 @@ def wait_ready(self): for it in range(self._server_poll_count): if not self.is_ready(): if self.driver == "atom": - poll_out = self.orch.exec(f"tail -30 {shlex.quote(self.server_log)}") + poll_out = self._tail_server_logs(30) for host, output in poll_out.items(): if self.EARLY_FAILURE_RE.search(output or ""): - raise RuntimeError( - f"atom server early failure on {host}: {output[-500:]}" - ) + raise RuntimeError(f"atom server early failure on {host}: {output[-500:]}") time.sleep(self._server_poll_wait) continue log.info("server health ready (iter=%d)", it) @@ -327,16 +480,13 @@ def wait_ready(self): def stop_server(self): if self.driver == "atom": log.info("stopping atom server") - self.orch.exec( + self._exec_all( "bash -c " - + shlex.quote( - "pkill -f 'atom.entrypoints.openai_server' || " - "pkill -f 'openai_server' || true" - ) + + shlex.quote("pkill -f 'atom.entrypoints.openai_server' || pkill -f 'openai_server' || true") ) else: log.info("stopping vllm server") - self.orch.exec("bash -c 'pkill -f \"vllm serve\" || true'") + self._exec_all("bash -c 'pkill -f \"vllm serve\" || true'") time.sleep(5) def _atom_client_argv(self): @@ -429,21 +579,21 @@ def _vllm_client_argv(self): def _clear_stale_result_artifact(self): """Remove a prior run's result file so poll logic cannot treat it as complete.""" artifact = shlex.quote(self._result_artifact) - self.orch.exec(f"rm -f {artifact}") + self._exec_head(f"rm -f {artifact}") def run_client(self): self._clear_stale_result_artifact() args = self._atom_client_argv() if self.driver == "atom" else self._vllm_client_argv() bench_cmd = " ".join(shlex.quote(str(a)) for a in args) client_cmd = f"source /tmp/server_env_script.sh && {bench_cmd} > {shlex.quote(self.client_log)} 2>&1 &" - self.orch.exec("bash -c " + shlex.quote(client_cmd)) + self._exec_head("bash -c " + shlex.quote(client_cmd)) def _atom_result_ready(self): - out = self.orch.exec(f"test -s {shlex.quote(self._result_artifact)} && echo OK || echo NO") + out = self._exec_head(f"test -s {shlex.quote(self._result_artifact)} && echo OK || echo NO") return bool(out) and all("OK" in (v or "") for v in out.values()) def _client_log_failures(self, tail_lines=2000): - out = self.orch.exec(f"tail -{tail_lines} {shlex.quote(self.client_log)}") + out = self._exec_head(f"tail -{tail_lines} {shlex.quote(self.client_log)}") failed = [] for host, output in out.items(): txt = output or "" @@ -497,7 +647,7 @@ def wait_client_complete(self): log.info("client complete (iter=%d)", it) return else: - out = self.orch.exec(f"tail -2000 {shlex.quote(self.client_log)}") + out = self._exec_head(f"tail -2000 {shlex.quote(self.client_log)}") done = [bool(self.COMPLETION_RE.search(txt or "")) for txt in out.values()] if done and all(done): log.info("client complete (iter=%d)", it) @@ -506,7 +656,7 @@ def wait_client_complete(self): raise RuntimeError("client did not complete before poll cap") def parse_results(self): - out = self.orch.exec(f"cat {shlex.quote(self._result_artifact)}") + out = self._exec_head(f"cat {shlex.quote(self._result_artifact)}") results = {} for host, text in out.items(): text = (text or "").strip() @@ -515,11 +665,15 @@ def parse_results(self): try: raw = json.loads(text) except (json.JSONDecodeError, ValueError) as e: - raise RuntimeError( - f"unparseable results artifact on {host}: {self._result_artifact}: {e}" - ) from e + raise RuntimeError(f"unparseable results artifact on {host}: {self._result_artifact}: {e}") from e if self.driver == "atom": raw.setdefault("random_input_len", int(self.isl)) raw.setdefault("random_output_len", int(self.osl)) - results[host] = to_client_metrics(raw, tp=self.tp, isl=self.isl) + results[host] = to_client_metrics( + raw, + tp=self.tp, + isl=self.isl, + scaling_baseline_output_throughput=self._scaling_baseline, + nnodes=self.nnodes, + ) return results diff --git a/cvs/lib/inference/unittests/fake_orch.py b/cvs/lib/inference/unittests/fake_orch.py index 2edc75488..22e60b401 100644 --- a/cvs/lib/inference/unittests/fake_orch.py +++ b/cvs/lib/inference/unittests/fake_orch.py @@ -10,10 +10,17 @@ class FakeOrch: - def __init__(self, exec_return=None): + def __init__(self, exec_return=None, hosts=None, exec_on_head_return=None): + self.hosts = list(hosts or ["node0"]) self.exec_return = exec_return if exec_return is not None else {} + self.exec_on_head_return = exec_on_head_return if exec_on_head_return is not None else self.exec_return self.commands = [] + self.exec_on_head_commands = [] - def exec(self, cmd, **kwargs): - self.commands.append(cmd) + def exec(self, cmd, hosts=None, **kwargs): + self.commands.append((cmd, hosts)) return self.exec_return + + def exec_on_head(self, cmd, **kwargs): + self.exec_on_head_commands.append(cmd) + return self.exec_on_head_return diff --git a/cvs/lib/inference/unittests/test_inferencex_atom_config_loader.py b/cvs/lib/inference/unittests/test_inferencex_atom_config_loader.py index 142fe8aed..68a5344ea 100644 --- a/cvs/lib/inference/unittests/test_inferencex_atom_config_loader.py +++ b/cvs/lib/inference/unittests/test_inferencex_atom_config_loader.py @@ -29,20 +29,50 @@ class TestInferenceXAtomConfigLoader(unittest.TestCase): def test_load_mi300x_sample_config(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json" + "input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json" ) variant = load_variant(config, _cluster_dict()) - self.assertEqual(variant.framework, "inferencex_atom_single") + self.assertEqual(variant.framework, "inferencex_atom") self.assertEqual(variant.params.driver, "vllm") self.assertEqual(variant.expected_cells(), ["ISL=7168,OSL=1024,TP=8,CONC=64"]) self.assertIn("enforce-eager", variant.roles.server.serve_args) + def test_deprecated_framework_alias_normalizes(self): + sweep = Sweep( + sequence_combinations=[SeqCombo(name="w1", isl="1024", osl="1024")], + runs=[Run(combo="w1", concurrency=128)], + ) + variant = InferenceXAtomVariantConfig( + schema_version=1, + framework="inferencex_atom_single", + gpu_arch="mi300x", + enforce_thresholds=False, + paths={ + "shared_fs": "/home/x", + "models_dir": "/home/x/models", + "log_dir": "/home/x/LOGS", + "hf_token_file": "/home/x/.hf", + }, + model={"id": "deepseek-ai/DeepSeek-R1-0528", "remote": 0, "precision": "fp8"}, + container={ + "name": "c", + "image": "img", + "runtime": {"name": "docker", "args": {"volumes": ["/home/x:/home/x"]}}, + }, + params={ + "driver": "atom", + "tensor_parallelism": "8", + "num_prompts": "100", + }, + sweep=sweep, + thresholds={}, + ) + self.assertEqual(variant.framework, "inferencex_atom") + def test_load_w1_mi300x_atom_variant(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" + "input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" ) variant = load_variant(config, _cluster_dict()) self.assertEqual(variant.threshold_json, "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_threshold.json") @@ -67,10 +97,49 @@ def test_load_w1_mi300x_atom_variant(self): ): self.assertIn(key, variant.thresholds[cell]) + def test_load_w1_mi300x_multinode_variant(self): + root = Path(__file__).resolve().parents[3] + config = root / ( + "input/config_file/inference/inferencex_atom/" + "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json" + ) + variant = load_variant(config, _cluster_dict()) + self.assertEqual(variant.params.nnodes, "2") + self.assertEqual(variant.params.pipeline_parallel_size, "2") + self.assertEqual(variant.params.scaling_baseline_output_throughput, "1500") + self.assertTrue(variant.enforce_thresholds) + self.assertEqual(len(variant.expected_cells()), 15) + cell = "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16" + self.assertIn(cell, variant.expected_cells()) + self.assertEqual( + variant.thresholds[cell]["scaling.efficiency_pct"], + {"kind": "min", "value": 50}, + ) + + def test_load_w1_mi355x_multinode_variant(self): + root = Path(__file__).resolve().parents[3] + config = root / ( + "input/config_file/inference/inferencex_atom/" + "mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_multi_config.json" + ) + variant = load_variant(config, _cluster_dict()) + self.assertEqual(variant.gpu_arch, "mi355x") + self.assertEqual(variant.params.nnodes, "2") + self.assertEqual(variant.params.pipeline_parallel_size, "2") + self.assertEqual(variant.params.scaling_baseline_output_throughput, "4000") + self.assertFalse(variant.enforce_thresholds) + self.assertEqual(len(variant.expected_cells()), 15) + cell = "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16" + self.assertIn(cell, variant.expected_cells()) + self.assertEqual( + variant.thresholds[cell]["scaling.efficiency_pct"], + {"kind": "min", "value": 50}, + ) + def test_load_w1_mi300x_smoke_variant(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" + "input/config_file/inference/inferencex_atom/" "mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json" ) variant = load_variant(config, _cluster_dict()) @@ -80,8 +149,7 @@ def test_load_w1_mi300x_smoke_variant(self): def test_load_w1_mi355x_atom_perf_variant_and_thresholds(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" + "input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" ) variant = load_variant(config, _cluster_dict()) self.assertEqual(variant.gpu_arch, "mi355x") @@ -103,8 +171,7 @@ def test_load_w1_mi355x_atom_perf_variant_and_thresholds(self): def test_load_w1_mi355x_atom_mtp3_inline_bench_args(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json" + "input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json" ) variant = load_variant(config, _cluster_dict()) self.assertIn("--method", variant.roles.server.atom_args) @@ -113,8 +180,7 @@ def test_load_w1_mi355x_atom_mtp3_inline_bench_args(self): def test_load_w1_mi355x_atom_mtp3_thresholds(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json" + "input/config_file/inference/inferencex_atom/mi355x_inferencex-atom-single_deepseek-r1_fp8_mtp3_config.json" ) variant = load_variant(config, _cluster_dict()) cell = "ISL=1024,OSL=1024,TP=8,CONC=256" @@ -133,7 +199,7 @@ def test_orchestrator_container_includes_server_env(self): } variant = InferenceXAtomVariantConfig( schema_version=1, - framework="inferencex_atom_single", + framework="inferencex_atom", gpu_arch="mi300x", enforce_thresholds=False, paths={ @@ -159,8 +225,7 @@ def test_orchestrator_container_includes_server_env(self): def test_expand_sweep_matches_w1_perf(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" + "input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" ) import json @@ -174,8 +239,7 @@ def test_expand_sweep_matches_w1_perf(self): def test_w1_perf_threshold_health_gates_tight_when_enforcing(self): root = Path(__file__).resolve().parents[3] config = root / ( - "input/config_file/inference/inferencex_atom_single/" - "mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" + "input/config_file/inference/inferencex_atom/mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json" ) variant = load_variant(config, _cluster_dict()) self.assertTrue(variant.enforce_thresholds) @@ -199,7 +263,7 @@ def test_atom_driver_requires_inline_atom_args(self): with self.assertRaises(ValueError): InferenceXAtomVariantConfig( schema_version=1, - framework="inferencex_atom_single", + framework="inferencex_atom", gpu_arch="mi300x", enforce_thresholds=False, paths={ @@ -239,6 +303,124 @@ def test_expand_sweep_parametrize_tier_ids(self): _, _, ids = expand_sweep_parametrize(sweep, ("metric_tier",)) self.assertIn("w1-conc128-throughput", ids) + def test_load_w1_mi300x_vllm_parity_variant(self): + root = Path(__file__).resolve().parents[3] + config = root / ( + "input/config_file/inference/inferencex_atom/" + "mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_config.json" + ) + variant = load_variant(config, _cluster_dict()) + self.assertEqual(variant.framework, "inferencex_atom_vllm_single") + self.assertEqual(variant.params.driver, "vllm") + self.assertIn("trust-remote-code", variant.roles.server.serve_args) + self.assertEqual( + variant.expected_cells(), + ["ISL=1024,OSL=1024,TP=8,CONC=128", "ISL=1024,OSL=1024,TP=8,CONC=256"], + ) + + def test_load_w1_mi300x_vllm_multinode_variant(self): + root = Path(__file__).resolve().parents[3] + config = root / ( + "input/config_file/inference/inferencex_atom/" + "mi300x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json" + ) + variant = load_variant(config, _cluster_dict()) + self.assertEqual(variant.framework, "inferencex_atom_vllm_single") + self.assertEqual(variant.params.driver, "vllm") + self.assertEqual(variant.params.nnodes, "2") + self.assertEqual(variant.params.pipeline_parallel_size, "2") + self.assertEqual(variant.params.scaling_baseline_output_throughput, "1500") + self.assertFalse(variant.enforce_thresholds) + self.assertEqual(len(variant.expected_cells()), 15) + cell = "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16" + self.assertIn(cell, variant.expected_cells()) + self.assertEqual( + variant.thresholds[cell]["scaling.efficiency_pct"], + {"kind": "min", "value": 50}, + ) + self.assertEqual( + variant.thresholds[cell]["compare.vllm.output_throughput_ratio"], + {"kind": "min", "value": 0.85}, + ) + + def test_load_w1_mi355x_vllm_multinode_variant(self): + root = Path(__file__).resolve().parents[3] + config = root / ( + "input/config_file/inference/inferencex_atom/" + "mi355x_inferencex-atom-single_deepseek-r1_fp8_vllm_perf_multi_config.json" + ) + variant = load_variant(config, _cluster_dict()) + self.assertEqual(variant.gpu_arch, "mi355x") + self.assertEqual(variant.framework, "inferencex_atom_vllm_single") + self.assertEqual(variant.params.driver, "vllm") + self.assertEqual(variant.params.nnodes, "2") + self.assertEqual(variant.params.scaling_baseline_output_throughput, "4000") + self.assertFalse(variant.enforce_thresholds) + cell = "ISL=512,OSL=512,TP=8,PP=2,NNODES=2,CONC=16" + self.assertIn(cell, variant.expected_cells()) + + def test_vllm_framework_rejects_atom_driver(self): + sweep = Sweep( + sequence_combinations=[SeqCombo(name="w1", isl="1024", osl="1024")], + runs=[Run(combo="w1", concurrency=128)], + ) + thresholds = {"ISL=1024,OSL=1024,TP=8,CONC=128": placeholder_gated_threshold_cell()} + with self.assertRaises(ValueError): + InferenceXAtomVariantConfig( + schema_version=1, + framework="inferencex_atom_vllm_single", + gpu_arch="mi300x", + enforce_thresholds=False, + paths={ + "shared_fs": "/home/x", + "models_dir": "/home/x/models", + "log_dir": "/home/x/LOGS", + "hf_token_file": "/home/x/.hf", + }, + model={"id": "deepseek-ai/DeepSeek-R1-0528", "remote": 0, "precision": "fp8"}, + container={ + "name": "c", + "image": "img", + "runtime": {"name": "docker", "args": {"volumes": ["/home/x:/home/x"]}}, + }, + roles={"server": {"serve_args": {"trust-remote-code": True}}}, + params={"driver": "atom", "tensor_parallelism": "8"}, + sweep=sweep, + thresholds=thresholds, + ) + + def test_server_session_key_differs_for_serve_args(self): + from types import SimpleNamespace + + base = SimpleNamespace( + model=SimpleNamespace(id="m"), + params=SimpleNamespace( + driver="vllm", + tensor_parallelism="8", + nnodes="1", + pipeline_parallel_size="1", + master_addr="", + master_port="29501", + ), + roles=SimpleNamespace(server=SimpleNamespace(serve_args={"kv-cache-dtype": "fp8"})), + ) + other = SimpleNamespace( + model=SimpleNamespace(id="m"), + params=SimpleNamespace( + driver="vllm", + tensor_parallelism="8", + nnodes="1", + pipeline_parallel_size="1", + master_addr="", + master_port="29501", + ), + roles=SimpleNamespace(server=SimpleNamespace(serve_args={"kv-cache-dtype": "bf16"})), + ) + self.assertNotEqual( + server_session_key(base, "1024", "1024"), + server_session_key(other, "1024", "1024"), + ) + if __name__ == "__main__": unittest.main() diff --git a/cvs/lib/inference/unittests/test_inferencex_atom_orch_parse.py b/cvs/lib/inference/unittests/test_inferencex_atom_orch_parse.py index 2911b183f..868cdfc22 100644 --- a/cvs/lib/inference/unittests/test_inferencex_atom_orch_parse.py +++ b/cvs/lib/inference/unittests/test_inferencex_atom_orch_parse.py @@ -21,10 +21,17 @@ _TP = 8 -def _fake_variant(*, driver="vllm"): +def _fake_variant( + *, driver="vllm", nnodes="1", pipeline_parallel_size="1", master_addr="", scaling_baseline_output_throughput="" +): params = SimpleNamespace( driver=driver, tensor_parallelism=str(_TP), + pipeline_parallel_size=pipeline_parallel_size, + nnodes=nnodes, + master_addr=master_addr, + master_port="29501", + scaling_baseline_output_throughput=scaling_baseline_output_throughput, port_no="8000", random_range_ratio="0.8", random_prefix_len="0", @@ -64,12 +71,8 @@ def test_parse_results_maps_client_metrics(self): w = raw self.assertIn("client.output_throughput", metrics) self.assertIn("client.mean_ttft_ms", metrics) - self.assertAlmostEqual( - metrics["client.per_gpu_throughput"], w["total_token_throughput"] / _TP - ) - self.assertAlmostEqual( - metrics["client.output_tput_per_gpu"], w["output_throughput"] / _TP - ) + self.assertAlmostEqual(metrics["client.per_gpu_throughput"], w["total_token_throughput"] / _TP) + self.assertAlmostEqual(metrics["client.output_tput_per_gpu"], w["output_throughput"] / _TP) self.assertEqual(metrics["client.p99_ttft_ms"], w["p99_ttft_ms"]) def test_parse_results_w1_tail_metrics_from_widened_fixture(self): @@ -114,10 +117,10 @@ def test_run_client_clears_stale_result_artifact(self): num_prompts=1000, ) job.run_client() - rm_cmds = [c for c in orch.commands if c.startswith("rm -f ")] + rm_cmds = [c for c, _ in orch.commands if c.startswith("rm -f ")] self.assertEqual(len(rm_cmds), 1) self.assertIn(job._result_artifact, rm_cmds[0]) - self.assertTrue(any("benchmark_serving" in c for c in orch.commands)) + self.assertTrue(any("benchmark_serving" in c for c, _ in orch.commands)) def test_parse_results_empty_artifact_raises(self): job = InferenceXAtomJob( @@ -177,7 +180,7 @@ def test_build_server_cmd_suppresses_gpu_memory_env_vars(self): num_prompts=100, ) job.build_server_cmd() - env_cmd = orch.commands[0] + env_cmd = orch.commands[0][0] self.assertNotIn("CVS_GPU_MEMORY_UTIL", env_cmd) self.assertNotIn("VLLM_GPU_MEMORY_UTIL", env_cmd) self.assertNotIn("VLLM_ENFORCE_EAGER", env_cmd) @@ -185,9 +188,7 @@ def test_build_server_cmd_suppresses_gpu_memory_env_vars(self): def test_client_log_failures_traceback(self): job = InferenceXAtomJob( - orch=FakeOrch( - exec_return={"node0": "Traceback (most recent call last):\n boom"} - ), + orch=FakeOrch(exec_return={"node0": "Traceback (most recent call last):\n boom"}), variant=_fake_variant(driver="atom"), hf_token="tok", isl="1024", @@ -255,6 +256,165 @@ def test_early_failure_regexes(self): self.assertTrue(job.CLIENT_LAUNCH_FAIL_RE.search("unrecognized arguments: --bad")) self.assertTrue(job.EARLY_FAILURE_RE.search("No such file or directory")) + def test_distributed_start_server_targets_each_host(self): + orch = FakeOrch(hosts=["10.0.0.1", "10.0.0.2"]) + job = InferenceXAtomJob( + orch=orch, + variant=_fake_variant(driver="atom", nnodes="2", pipeline_parallel_size="2", master_addr="10.0.0.1"), + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + job.build_server_cmd(clear_atom_cache=False) + job.start_server() + launch_cmds = [c for c, hosts in orch.commands if hosts] + self.assertEqual(len(launch_cmds), 2) + self.assertNotIn("--node-rank", launch_cmds[0]) + self.assertNotIn("--distributed-executor-backend", launch_cmds[0]) + self.assertIn("openai_server", launch_cmds[0]) + + def test_distributed_vllm_start_server_uses_node_rank_and_pp(self): + orch = FakeOrch(hosts=["10.0.0.1", "10.0.0.2"]) + job = InferenceXAtomJob( + orch=orch, + variant=_fake_variant(driver="vllm", nnodes="2", pipeline_parallel_size="2", master_addr="10.0.0.1"), + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + job.build_server_cmd() + job.start_server() + launch_cmds = [c for c, hosts in orch.commands if hosts] + self.assertEqual(len(launch_cmds), 2) + self.assertIn("vllm serve", launch_cmds[0]) + self.assertNotIn("openai_server", launch_cmds[0]) + self.assertIn("--node-rank 0", launch_cmds[0]) + self.assertIn("--node-rank 1", launch_cmds[1]) + self.assertIn("--nnodes 2", launch_cmds[0]) + self.assertIn("--pipeline-parallel-size 2", launch_cmds[0]) + self.assertIn("--master-addr 10.0.0.1", launch_cmds[0]) + self.assertIn("--distributed-executor-backend mp", launch_cmds[0]) + + def test_vllm_distributed_argv(self): + job = InferenceXAtomJob( + orch=FakeOrch(hosts=["10.0.0.1", "10.0.0.2"]), + variant=_fake_variant(driver="vllm", nnodes="2", pipeline_parallel_size="2", master_addr="10.0.0.1"), + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + argv = job._vllm_distributed_argv(rank=1) + self.assertEqual( + argv, + [ + "--node-rank", + "1", + "--master-addr", + "10.0.0.1", + "--master-port", + "29501", + "--nnodes", + "2", + "--pipeline-parallel-size", + "2", + "--distributed-executor-backend", + "mp", + ], + ) + + def test_distributed_atom_spmd_env_and_dp_when_tp_allows(self): + orch = FakeOrch(hosts=["10.0.0.1", "10.0.0.2"]) + variant = _fake_variant(driver="atom", nnodes="2", pipeline_parallel_size="2", master_addr="10.0.0.1") + variant.params.tensor_parallelism = "4" + variant.roles.server.atom_args = ["-tp", "4"] + job = InferenceXAtomJob( + orch=orch, + variant=variant, + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + job.start_server() + launch_cmds = [c for c, hosts in orch.commands if hosts] + self.assertIn("-dp 2", launch_cmds[0]) + self.assertIn("ATOM_DP_RANK=0", launch_cmds[0]) + self.assertIn("ATOM_DP_RANK=1", launch_cmds[1]) + self.assertIn("ATOM_DP_MASTER_IP=10.0.0.1", launch_cmds[0]) + + def test_distributed_atom_tp8_multinode_never_passes_vllm_flags(self): + orch = FakeOrch(hosts=["10.0.0.1", "10.0.0.2"]) + variant = _fake_variant(driver="atom", nnodes="2", pipeline_parallel_size="2", master_addr="10.0.0.1") + variant.roles.server.atom_args = [ + "-tp", + "8", + "--node-rank", + "1", + "--pipeline-parallel-size", + "2", + ] + job = InferenceXAtomJob( + orch=orch, + variant=variant, + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + argv = job._atom_server_argv(rank=1) + joined = " ".join(argv) + self.assertNotIn("--node-rank", joined) + self.assertNotIn("--pipeline-parallel-size", joined) + self.assertNotIn("--master-addr", joined) + self.assertIn("-tp 8", joined) + job.start_server() + launch_cmds = [c for c, hosts in orch.commands if hosts] + self.assertNotIn("--node-rank", launch_cmds[1]) + self.assertNotIn("--pipeline-parallel-size", launch_cmds[1]) + + def test_distributed_client_uses_exec_on_head(self): + orch = FakeOrch(hosts=["10.0.0.1", "10.0.0.2"]) + job = InferenceXAtomJob( + orch=orch, + variant=_fake_variant(driver="atom", nnodes="2", pipeline_parallel_size="2"), + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + job.run_client() + self.assertEqual(len(orch.exec_on_head_commands), 2) + self.assertTrue(any("benchmark_serving" in c for c in orch.exec_on_head_commands)) + + def test_parse_results_scaling_efficiency(self): + raw = json.loads((_FIXTURES / "vllm_results_sample.json").read_text()) + job = InferenceXAtomJob( + orch=FakeOrch(exec_on_head_return={"head": json.dumps(raw)}), + variant=_fake_variant( + driver="atom", + nnodes="2", + scaling_baseline_output_throughput="100", + ), + hf_token="tok", + isl="1024", + osl="1024", + concurrency=128, + num_prompts=100, + ) + metrics = job.parse_results()["head"] + self.assertIn("scaling.efficiency_pct", metrics) + expected = (raw["output_throughput"] / (100.0 * 2)) * 100.0 + self.assertAlmostEqual(metrics["scaling.efficiency_pct"], expected) + if __name__ == "__main__": unittest.main() diff --git a/cvs/lib/inference/unittests/test_inferencex_atom_parsing.py b/cvs/lib/inference/unittests/test_inferencex_atom_parsing.py index db2447f1d..4d8c2e0e0 100644 --- a/cvs/lib/inference/unittests/test_inferencex_atom_parsing.py +++ b/cvs/lib/inference/unittests/test_inferencex_atom_parsing.py @@ -51,6 +51,34 @@ def test_tier_metric_specs_record_includes_non_tiered(self): self.assertIn("client.median_ttft_ms", specs) self.assertNotIn("client.output_throughput", specs) + def test_tier_metric_specs_scaling(self): + cell = { + "scaling.efficiency_pct": {"kind": "min", "value": 50}, + "client.output_throughput": {"kind": "min_tok_s", "value": 1}, + } + specs = tier_metric_specs(cell, "scaling") + self.assertEqual(specs, {"scaling.efficiency_pct": {"kind": "min", "value": 50}}) + + def test_tier_metric_specs_compare_vllm(self): + cell = { + "compare.vllm.output_throughput_ratio": {"kind": "min", "value": 0.85}, + "client.output_throughput": {"kind": "min_tok_s", "value": 1}, + } + specs = tier_metric_specs(cell, "compare") + self.assertEqual( + specs, + {"compare.vllm.output_throughput_ratio": {"kind": "min", "value": 0.85}}, + ) + + def test_compare_vllm_metrics(self): + from cvs.lib.inference.utils.inferencex_atom_parsing import compare_vllm_metrics + + actual = {"client.output_throughput": 2000, "client.mean_ttft_ms": 440} + reference = {"client.output_throughput": 2500, "client.mean_ttft_ms": 400} + out = compare_vllm_metrics(actual, reference) + self.assertAlmostEqual(out["compare.vllm.output_throughput_ratio"], 0.8) + self.assertAlmostEqual(out["compare.vllm.mean_ttft_ms_ratio"], 1.1) + def test_gated_metrics_subset_of_client_metrics(self): client_short = {short for short, _unit in CLIENT_METRICS} missing = GATED_METRICS - client_short diff --git a/cvs/lib/inference/utils/docs/inferencex-atom-parsing.md b/cvs/lib/inference/utils/docs/inferencex-atom-parsing.md index 2ef1c2ded..3e68cb0a1 100644 --- a/cvs/lib/inference/utils/docs/inferencex-atom-parsing.md +++ b/cvs/lib/inference/utils/docs/inferencex-atom-parsing.md @@ -24,4 +24,4 @@ same artifact keys. - `inferencex_atom_orch.InferenceXAtomJob.parse_results` - `inferencex_atom_config_loader` threshold coverage (`gated_metrics=GATED_METRICS`) -- `cvs.tests.inference.inferencex_atom.inferencex_atom_single` — `test_cell_metrics` tiers (throughput, ttft, tpot, health, record) +- `cvs.tests.inference.inferencex_atom.inferencex_atom` — `test_cell_metrics` tiers (throughput, ttft, tpot, health, record) diff --git a/cvs/lib/inference/utils/inferencex_atom_config_loader.py b/cvs/lib/inference/utils/inferencex_atom_config_loader.py index 535bc7c0e..4f7723558 100644 --- a/cvs/lib/inference/utils/inferencex_atom_config_loader.py +++ b/cvs/lib/inference/utils/inferencex_atom_config_loader.py @@ -2,7 +2,7 @@ Copyright 2025 Advanced Micro Devices, Inc. All rights reserved. -InferenceX ATOM suite config schema (``framework: inferencex_atom_single``). +InferenceX ATOM suite config schema (``inferencex_atom`` / ``inferencex_atom_vllm_single``). Generic paths/model/container/threshold plumbing lives in :mod:`cvs.lib.utils.config_loader`. Sweep selector types are shared with @@ -13,7 +13,7 @@ from typing import Any, Dict, List -from pydantic import model_validator +from pydantic import field_validator, model_validator from typing_extensions import Literal from cvs.lib.inference.utils.inferencing_config_loader import ( @@ -66,16 +66,38 @@ class InferenceXAtomParams(_Forbid): bench_max_failed_requests: str = "0" bench_extra_args: str = "" result_filename: str = "results" + # Multinode (M5): omit or set nnodes=1 for single-node runs. When nnodes>1, + # cluster node_dict must list the same number of hosts and test_setup_sshd runs. + nnodes: str = "1" + pipeline_parallel_size: str = "1" + master_addr: str = "" + master_port: str = "29501" + # Optional single-node reference output_throughput for scaling.efficiency_pct. + scaling_baseline_output_throughput: str = "" class InferenceXAtomRunCard(_Forbid): upstream_run_url: str = "" atom_image_pin: str = "" + vllm_image_pin: str = "" notes: str = "" + # Optional ATOM reference metrics JSON (cell_key -> client.* scalars) for M4 parity gates. + parity_reference_json: str = "" + + +INFERENCEX_ATOM_FRAMEWORKS = ("inferencex_atom", "inferencex_atom_vllm_single") class InferenceXAtomVariantConfig(BaseVariantConfig): - framework: Literal["inferencex_atom_single"] + framework: Literal["inferencex_atom", "inferencex_atom_vllm_single"] + + @field_validator("framework", mode="before") + @classmethod + def _normalize_deprecated_framework(cls, value): + if value == "inferencex_atom_single": + return "inferencex_atom" + return value + gpu_arch: str run_card: InferenceXAtomRunCard = InferenceXAtomRunCard() roles: InferenceXAtomRoles = InferenceXAtomRoles() @@ -83,14 +105,17 @@ class InferenceXAtomVariantConfig(BaseVariantConfig): sweep: Sweep def cell_key(self, isl, osl, concurrency): - return f"ISL={isl},OSL={osl},TP={self.params.tensor_parallelism},CONC={concurrency}" + p = self.params + key = f"ISL={isl},OSL={osl},TP={p.tensor_parallelism}" + if int(p.pipeline_parallel_size) > 1 or int(p.nnodes) > 1: + key += f",PP={p.pipeline_parallel_size}" + if int(p.nnodes) > 1: + key += f",NNODES={p.nnodes}" + return f"{key},CONC={concurrency}" def expected_cells(self) -> List[str]: by_name = {c.name: c for c in self.sweep.sequence_combinations} - return [ - self.cell_key(by_name[r.combo].isl, by_name[r.combo].osl, r.concurrency) - for r in self.sweep.runs - ] + return [self.cell_key(by_name[r.combo].isl, by_name[r.combo].osl, r.concurrency) for r in self.sweep.runs] @model_validator(mode="after") def _check_thresholds_cover_sweep(self): @@ -100,6 +125,22 @@ def _check_thresholds_cover_sweep(self): enforce_thresholds=self.enforce_thresholds, gated_metrics=GATED_METRICS, ) + if int(self.params.nnodes) > 1 and (self.params.scaling_baseline_output_throughput or "").strip(): + missing = [] + for cell in self.expected_cells(): + specs = self.thresholds.get(cell) or {} + if "scaling.efficiency_pct" not in specs: + missing.append(cell) + if missing: + msg = ( + "multinode variant with scaling_baseline_output_throughput requires " + f"scaling.efficiency_pct in every cell; missing: {missing}" + ) + if self.enforce_thresholds: + raise ValueError(msg) + import warnings + + warnings.warn(f"{msg} (enforce_thresholds=false -> record-only)", stacklevel=2) return self @model_validator(mode="after") @@ -111,6 +152,20 @@ def _atom_driver_requires_inline_server_args(self): ) return self + @model_validator(mode="after") + def _framework_driver_consistency(self): + if self.framework == "inferencex_atom_vllm_single": + if self.params.driver != "vllm": + raise ValueError( + "framework='inferencex_atom_vllm_single' requires params.driver='vllm'" + ) + if not self.roles.server.serve_args: + raise ValueError( + "framework='inferencex_atom_vllm_single' requires " + "roles.server.serve_args (inline vLLM serve flags)" + ) + return self + def expand_sweep(sweep): """Expand a sweep into ``(cases, ids)`` for pytest parametrization.""" @@ -138,23 +193,60 @@ def reuse_server_flag(params) -> bool: return raw in ("true", "1", "yes") +def _serve_args_session_key(serve_args: dict) -> tuple: + return tuple(sorted((str(k), str(v)) for k, v in (serve_args or {}).items())) + + def server_session_key(variant_config, isl, osl): """Stable key for server reuse across sweep cells with identical model/shape.""" p = variant_config.params + server = variant_config.roles.server + if p.driver == "vllm": + server_tokens = _serve_args_session_key(server.serve_args) + else: + server_tokens = tuple(server.atom_args) return ( variant_config.model.id, p.driver, str(isl), str(osl), - tuple(variant_config.roles.server.atom_args), + server_tokens, p.tensor_parallelism, + p.nnodes, + p.pipeline_parallel_size, + p.master_addr, + p.master_port, ) -def expand_sweep_parametrize(sweep, fixturenames): +def load_parity_reference_cells(path: str) -> dict[str, dict]: + """Load cell_key -> metric dict from a parity reference JSON file.""" + if not (path or "").strip(): + return {} + from pathlib import Path + import json + + ref_path = Path(path) + if not ref_path.is_file(): + raise FileNotFoundError(f"parity reference not found: {path}") + data = json.loads(ref_path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError(f"parity reference must be a JSON object: {path}") + out: dict[str, dict] = {} + for key, value in data.items(): + if str(key).startswith("_"): + continue + if not isinstance(value, dict): + raise ValueError(f"parity reference cell {key!r} must be an object") + out[str(key)] = value + return out + + +def expand_sweep_parametrize(sweep, fixturenames, *, metric_tier_order=None): """Build pytest parametrize args for inference or metric-tier collection.""" from cvs.lib.inference.utils.inferencex_atom_parsing import METRIC_TIER_ORDER + tiers = metric_tier_order or METRIC_TIER_ORDER cases, ids = expand_sweep(sweep) if "metric_tier" in fixturenames: if not cases: @@ -162,7 +254,7 @@ def expand_sweep_parametrize(sweep, fixturenames): tier_cases = [] tier_ids = [] for (combo, c), cid in zip(cases, ids): - for tier in METRIC_TIER_ORDER: + for tier in tiers: tier_cases.append((combo, c, tier)) tier_ids.append(f"{cid}-{tier}") return ("seq_combo,concurrency,metric_tier", tier_cases, tier_ids) @@ -192,7 +284,6 @@ def placeholder_gated_threshold_cell( ) -> Dict[str, Any]: """Return one sweep cell's ``client.*`` specs covering every ``GATED_METRICS`` member.""" loose_ms = {"kind": "max_ms", "value": 1_000_000} - loose_tok = {"kind": "min_tok_s", "value": 0} return { "client.total_token_throughput": {"kind": "min_tok_s", "value": total_token_throughput_min}, "client.output_throughput": {"kind": "min_tok_s", "value": output_throughput_min}, diff --git a/cvs/lib/inference/utils/inferencex_atom_parsing.py b/cvs/lib/inference/utils/inferencex_atom_parsing.py index e31f930b5..e6f18170a 100644 --- a/cvs/lib/inference/utils/inferencex_atom_parsing.py +++ b/cvs/lib/inference/utils/inferencex_atom_parsing.py @@ -57,34 +57,89 @@ "success_rate", "failed", ), + "scaling": ("efficiency_pct",), +} + +SCALING_METRICS: tuple[str, ...] = METRIC_TIERS["scaling"] +SCALING_METRIC_UNITS: dict[str, str] = {"efficiency_pct": "%"} + +COMPARE_VLLM_METRICS: tuple[str, ...] = ( + "output_throughput_ratio", + "mean_ttft_ms_ratio", +) +COMPARE_VLLM_METRIC_UNITS: dict[str, str] = { + "output_throughput_ratio": "ratio", + "mean_ttft_ms_ratio": "ratio", } METRIC_TIER_ORDER: tuple[str, ...] = tuple(METRIC_TIERS.keys()) + ("record",) +VLLM_METRIC_TIER_ORDER: tuple[str, ...] = tuple(METRIC_TIERS.keys()) + ("compare", "record") _tiered = {m for names in METRIC_TIERS.values() for m in names} -RECORD_METRICS: tuple[str, ...] = tuple( - short for short, _unit in CLIENT_METRICS if short not in _tiered -) +RECORD_METRICS: tuple[str, ...] = tuple(short for short, _unit in CLIENT_METRICS if short not in _tiered) ENFORCED_METRICS = frozenset(_tiered) -def to_client_metrics(raw, *, tp, isl): +def scaling_efficiency_pct(actual_output_throughput, *, baseline_single_node, nnodes): + """Linear scaling efficiency: actual / (single-node baseline × nnodes).""" + denom = _safe_div(baseline_single_node, 1) + if denom is None or int(nnodes) < 1: + return None + ideal = denom * int(nnodes) + if ideal <= 0: + return None + return _safe_div(actual_output_throughput, ideal) + + +def to_client_metrics(raw, *, tp, isl, scaling_baseline_output_throughput=None, nnodes=1): """Map an ATOM ``results.json`` dict to the ``client.*`` namespace for IX.""" m = _vllm_to_client_metrics(raw, tp=tp, isl=isl) m["client.output_tput_per_gpu"] = _safe_div(raw.get("output_throughput"), tp) + if scaling_baseline_output_throughput is not None: + eff = scaling_efficiency_pct( + raw.get("output_throughput"), + baseline_single_node=scaling_baseline_output_throughput, + nnodes=nnodes, + ) + if eff is not None: + m["scaling.efficiency_pct"] = eff * 100.0 return m +def compare_vllm_metrics(actual: dict, reference: dict) -> dict[str, float]: + """M4 parity ratios: vLLM cell metrics relative to ATOM reference cell.""" + out: dict[str, float] = {} + vllm_tput = actual.get("client.output_throughput") + atom_tput = reference.get("client.output_throughput") + ratio = _safe_div(vllm_tput, atom_tput) + if ratio is not None: + out["compare.vllm.output_throughput_ratio"] = ratio + vllm_ttft = actual.get("client.mean_ttft_ms") + atom_ttft = reference.get("client.mean_ttft_ms") + ratio = _safe_div(vllm_ttft, atom_ttft) + if ratio is not None: + out["compare.vllm.mean_ttft_ms_ratio"] = ratio + return out + + def tier_metric_specs(thresholds_cell: dict, tier: str) -> dict[str, dict]: - """Return ``client.*`` threshold specs for one tier in a sweep cell.""" + """Return threshold specs for one tier in a sweep cell.""" if tier == "record": names = RECORD_METRICS + prefix = "client." + elif tier == "scaling": + names = SCALING_METRICS + prefix = "scaling." + elif tier == "compare": + names = COMPARE_VLLM_METRICS + prefix = "compare.vllm." else: names = METRIC_TIERS.get(tier, ()) + prefix = "client." specs = {} for short in names: - full = f"client.{short}" + full = f"{prefix}{short}" spec = thresholds_cell.get(full) if spec is not None: specs[full] = spec diff --git a/cvs/lib/inference_lib.py b/cvs/lib/inference_lib.py index 217fea5fb..173cc3a0b 100644 --- a/cvs/lib/inference_lib.py +++ b/cvs/lib/inference_lib.py @@ -28,7 +28,7 @@ def __init__(self, *args, **kwargs): raise NotImplementedError( "InferenceMax is deprecated. Use ``cvs.lib.inference.inferencex_atom_orch.InferenceXAtomJob`` " "with ``ContainerOrchestrator`` from the tests under ``cvs.tests.inference.inferencex_atom`` " - "(``inferencex_atom_single`` suite and schema_version 1 configs)." + "(``inferencex_atom`` suite and schema_version 1 configs)." ) @@ -60,8 +60,7 @@ def _detect_framework(cls, inference_config_dict): """ if 'inferencemax_repo' in inference_config_dict: log.warning( - "inferencemax_repo detected; InferenceMax is deprecated — " - "use the inferencex_atom_single suite instead" + "inferencemax_repo detected; InferenceMax is deprecated — use the inferencex_atom suite instead" ) return 'inferencex_atom' elif 'vllm_script_path' in inference_config_dict: @@ -110,7 +109,7 @@ def create_job( framework_lower = framework.lower() if framework_lower == 'inferencemax': - log.warning("framework='inferencemax' is deprecated; use inferencex_atom_single") + log.warning("framework='inferencemax' is deprecated; use inferencex_atom") framework_lower = 'inferencex_atom' if framework_lower not in cls._FRAMEWORK_CLASSES: diff --git a/cvs/lib/report/README.md b/cvs/lib/report/README.md index a57fc1fef..f2e59429b 100644 --- a/cvs/lib/report/README.md +++ b/cvs/lib/report/README.md @@ -4,9 +4,8 @@ CVS can attach an HTML/JSON **suite report** to pytest runs that use `--html`. R generated at **session end** and bundled into the same results zip as the pytest HTML report. They are **render-only** — they do not change pass/fail or threshold enforcement. -**IX-atom reference:** `presets/inferencex_atom.py` + shim `presets/inferencex_atom_single.py` -(auto-loaded for `cvs run inferencex_atom_single`). Suite owners also see Step 8 in -`cvs/lib/inference/ADDING_A_SUITE.md`. +**IX-atom reference:** `presets/inferencex_atom.py` (auto-loaded for `cvs run inferencex_atom`). +Suite owners also see Step 8 in `cvs/lib/inference/ADDING_A_SUITE.md`. ## Quick start @@ -25,8 +24,10 @@ Your suite must already collect: | `variant_config` | Thresholds, `enforce_thresholds`, `cell_key(isl, osl, conc)` | | `lifecycle` | `.record(nodeid, label, seconds)` on server/client stages | +## Unit tests + ```bash -cvs run inferencex_atom_single --cluster_file ... --config_file ... --html=~/cvs_results/run.html +cvs run inferencex_atom --cluster_file ... --config_file ... --html=~/cvs_results/run.html python -m pytest cvs/lib/report/unittests/ -q ``` diff --git a/cvs/lib/report/cell_build.py b/cvs/lib/report/cell_build.py index 38e7e742f..a34313d7d 100644 --- a/cvs/lib/report/cell_build.py +++ b/cvs/lib/report/cell_build.py @@ -141,20 +141,15 @@ def build_cell_record( "label": label, "metric": full, "actual": actual, - "unit": config.metric_units.get(short, ""), + "unit": config.metric_units.get(short.rsplit(".", 1)[-1], ""), "spec": spec, "status": metric_pass(full, actual, spec) if enforce and spec else "record", - "bar_pct": bar_pct(float(actual), spec) - if spec is not None and actual is not None - else None, + "bar_pct": bar_pct(float(actual), spec) if spec is not None and actual is not None else None, "margin": margin_text(actual, spec) if spec else None, } ) - tiers = { - tier: tier_status(config, actuals, thresholds_cell, tier, enforce) - for tier in config.metric_tier_order - } + tiers = {tier: tier_status(config, actuals, thresholds_cell, tier, enforce) for tier in config.metric_tier_order} pytest_links = resolve_pytest_nodeids_for_cell(config, lifecycle_report, conc) return { @@ -183,7 +178,10 @@ def build_all_cells( lifecycle_report: Mapping[str, list], ) -> List[dict]: cells: List[dict] = [] - for key, host_dict in sorted(inf_res_dict.items(), key=lambda kv: (kv[0][4], kv[0][5]) if isinstance(kv[0], tuple) and len(kv[0]) >= 6 else (0, 0)): + for key, host_dict in sorted( + inf_res_dict.items(), + key=lambda kv: (kv[0][4], kv[0][5]) if isinstance(kv[0], tuple) and len(kv[0]) >= 6 else (0, 0), + ): if not isinstance(key, tuple) or len(key) != 6: continue if not isinstance(host_dict, dict) or not host_dict: diff --git a/cvs/lib/report/inference_payload.py b/cvs/lib/report/inference_payload.py index 9a1f8e509..3b91d8ccb 100644 --- a/cvs/lib/report/inference_payload.py +++ b/cvs/lib/report/inference_payload.py @@ -68,9 +68,7 @@ def sweep_has_multi_shape_comparison(cells: List[dict]) -> bool: return len(shapes) >= 2 and len(concurrencies) >= 2 -def build_chart_series( - config: InferenceReportConfig, cells: List[dict] -) -> Dict[str, List[dict]]: +def build_chart_series(config: InferenceReportConfig, cells: List[dict]) -> Dict[str, List[dict]]: """Per-metric sweep charts grouped by ISL/OSL shape. Each metric maps to a list of ``{isl, osl, label, points}`` entries so @@ -80,7 +78,7 @@ def build_chart_series( groups = group_cells_by_shape(cells) series: Dict[str, List[dict]] = {} for chart in config.chart_series: - full = config.full_metric(chart.metric_suffix) + full = chart.metric_key or config.full_metric(chart.metric_suffix) group_entries: List[dict] = [] for (isl, osl), group_cells in sorted(groups.items()): values_by_conc = metric_values_by_concurrency(group_cells, full) @@ -180,11 +178,7 @@ def _build_run_card_display( run_card_rows.append((label, value, is_link)) run_card_display = extend_run_card_display(run_card_rows, prov) - run_card_display = [ - (label, value, is_link) - for label, value, is_link in run_card_display - if label != "CVS version" - ] + run_card_display = [(label, value, is_link) for label, value, is_link in run_card_display if label != "CVS version"] display_labels = {label for label, _value, _link in run_card_display} if prov.get("cvs_version") and "CVS" not in display_labels: run_card_display.append(("CVS", str(prov["cvs_version"]), False)) @@ -246,9 +240,7 @@ def build_inference_report_payload( if cvs_version: prov.setdefault("cvs_version", cvs_version) - run_card_display, run_card_notes, generated_at = _build_run_card_display( - config, variant_config, prov - ) + run_card_display, run_card_notes, generated_at = _build_run_card_display(config, variant_config, prov) chart_series = build_chart_series(config, cells) panels = _build_panels(config, cells, report_dir) diff --git a/cvs/lib/report/presets/_inference_suite_template.py b/cvs/lib/report/presets/_inference_suite_template.py index f7ba8b32e..dfb24aa6e 100644 --- a/cvs/lib/report/presets/_inference_suite_template.py +++ b/cvs/lib/report/presets/_inference_suite_template.py @@ -5,9 +5,9 @@ **Copy this file** to ``cvs/lib/report/presets/.py``. The filename must match the pytest module stem from ``cvs run `` (e.g. -``inferencex_atom_single`` → ``presets/inferencex_atom_single.py``). +``inferencex_atom`` → ``presets/inferencex_atom.py``). -**Reference:** ``inferencex_atom.py`` (full preset) + ``inferencex_atom_single.py`` (auto-load shim). +**Reference:** ``inferencex_atom.py`` (IX-atom preset; auto-loaded when ``cvs run inferencex_atom``). See ``cvs/lib/report/README.md`` for the IX-atom end-to-end example. Suite owners fill in the TODOs below, keep collecting ``inf_res_dict`` during tests, diff --git a/cvs/lib/report/presets/inferencex_atom.py b/cvs/lib/report/presets/inferencex_atom.py index e6aa1dc04..c8f013a02 100644 --- a/cvs/lib/report/presets/inferencex_atom.py +++ b/cvs/lib/report/presets/inferencex_atom.py @@ -15,6 +15,7 @@ from cvs.lib.inference.utils.inferencex_atom_parsing import ( CLIENT_METRIC_UNITS, METRIC_TIER_ORDER, + SCALING_METRIC_UNITS, tier_metric_specs, ) from cvs.lib.report.chart_presets import DEFAULT_PERF_CHART_SERIES @@ -23,6 +24,17 @@ provenance_link_rows, thresholds_run_card_row, ) +from cvs.lib.report.types import ReportChartSeries + +_INFERENCEX_ATOM_CHART_SERIES = ( + *DEFAULT_PERF_CHART_SERIES, + ReportChartSeries( + "efficiency_pct", + "Scaling efficiency", + "%", + metric_key="scaling.efficiency_pct", + ), +) def _atom_run_card_display(variant: Any, provenance: dict) -> List[Tuple[str, str, bool]]: @@ -46,12 +58,12 @@ def _atom_run_card_display(variant: Any, provenance: dict) -> List[Tuple[str, st report_basename="inferencex_atom_run_deck", title="IX Run Deck", subtitle="InferenceX ATOM \u00b7 lab performance summary", - footer="CVS inferencex_atom_single \u00b7 render-only \u00b7 does not affect gates", + footer="CVS inferencex_atom \u00b7 render-only \u00b7 does not affect gates", link_name="IX Run Deck", results_columns=INFERENCEX_ATOM_RESULTS_COLUMNS, metric_tier_order=METRIC_TIER_ORDER, tier_metric_specs=tier_metric_specs, - metric_units=CLIENT_METRIC_UNITS, + metric_units={**CLIENT_METRIC_UNITS, **SCALING_METRIC_UNITS}, metric_prefix="client.", cell_highlights=( ("output_throughput", "Output tok/s"), @@ -59,8 +71,9 @@ def _atom_run_card_display(variant: Any, provenance: dict) -> List[Tuple[str, st ("mean_tpot_ms", "Mean TPOT (ms)"), ("p99_ttft_ms", "P99 TTFT (ms)"), ("p95_tpot_ms", "P95 TPOT (ms)"), + ("scaling.efficiency_pct", "Scaling eff. (%)"), ), - chart_series=DEFAULT_PERF_CHART_SERIES, + chart_series=_INFERENCEX_ATOM_CHART_SERIES, inference_test_substring="test_inferencex_atom_inference", row_card_extras=False, row_card_test_names=("test_cell_metrics",), diff --git a/cvs/lib/report/presets/inferencex_atom_single.py b/cvs/lib/report/presets/inferencex_atom_single.py deleted file mode 100644 index c6f4642e3..000000000 --- a/cvs/lib/report/presets/inferencex_atom_single.py +++ /dev/null @@ -1,10 +0,0 @@ -''' -Copyright 2025 Advanced Micro Devices, Inc. -All rights reserved. - -Auto-loaded when running ``cvs run inferencex_atom_single`` (stem matches filename). -''' - -from cvs.lib.report.presets.inferencex_atom import ( - INFERENCEX_ATOM_REPORT_CONFIG as INFERENCEX_ATOM_SINGLE_REPORT_CONFIG, -) diff --git a/cvs/lib/report/presets/inferencex_atom_vllm.py b/cvs/lib/report/presets/inferencex_atom_vllm.py new file mode 100644 index 000000000..91bd5f7c6 --- /dev/null +++ b/cvs/lib/report/presets/inferencex_atom_vllm.py @@ -0,0 +1,67 @@ +''' +Copyright 2025 Advanced Micro Devices, Inc. +All rights reserved. + +Auto-loaded when running ``cvs run inferencex_atom_vllm_single``. +''' + +from cvs.lib.inference.inference_suite_results_table import INFERENCEX_ATOM_RESULTS_COLUMNS +from cvs.lib.inference.utils.inferencex_atom_parsing import ( + CLIENT_METRIC_UNITS, + COMPARE_VLLM_METRIC_UNITS, + SCALING_METRIC_UNITS, + VLLM_METRIC_TIER_ORDER, + tier_metric_specs, +) +from cvs.lib.report.presets.inferencex_atom import ( + _INFERENCEX_ATOM_CHART_SERIES, + _atom_run_card_display, + _CELL_LIFECYCLE, + _SESSION_LIFECYCLE, +) +from cvs.lib.report.types import InferenceReportConfig, ReportChartSeries + +_VLLM_PARITY_CHART_SERIES = ( + *_INFERENCEX_ATOM_CHART_SERIES, + ReportChartSeries( + "output_throughput_ratio", + "vLLM / ATOM output tput", + "ratio", + metric_key="compare.vllm.output_throughput_ratio", + ), +) + +_VLLM_RESULTS_COLUMNS = INFERENCEX_ATOM_RESULTS_COLUMNS + ( + ("vLLM/ATOM tput", "compare.vllm.output_throughput_ratio"), + ("vLLM/ATOM TTFT", "compare.vllm.mean_ttft_ms_ratio"), +) + +INFERENCEX_ATOM_VLLM_SINGLE_REPORT_CONFIG = InferenceReportConfig( + suite_id="inferencex_atom_vllm", + report_basename="inferencex_atom_vllm_run_deck", + title="IX Run Deck", + subtitle="InferenceX vLLM parity \u00b7 W1 reference sweep", + footer="CVS inferencex_atom_vllm_single \u00b7 render-only \u00b7 does not affect gates", + link_name="IX vLLM Run Deck", + results_columns=_VLLM_RESULTS_COLUMNS, + metric_tier_order=VLLM_METRIC_TIER_ORDER, + tier_metric_specs=tier_metric_specs, + metric_units={**CLIENT_METRIC_UNITS, **SCALING_METRIC_UNITS, **COMPARE_VLLM_METRIC_UNITS}, + metric_prefix="client.", + cell_highlights=( + ("output_throughput", "Output tok/s"), + ("mean_ttft_ms", "Mean TTFT (ms)"), + ("mean_tpot_ms", "Mean TPOT (ms)"), + ("compare.vllm.output_throughput_ratio", "vLLM/ATOM tput"), + ("compare.vllm.mean_ttft_ms_ratio", "vLLM/ATOM TTFT"), + ), + chart_series=_VLLM_PARITY_CHART_SERIES, + inference_test_substring="test_inferencex_atom_vllm_inference", + session_lifecycle_labels=_SESSION_LIFECYCLE, + cell_lifecycle_labels=_CELL_LIFECYCLE, + row_card_extras=False, + row_card_test_names=("test_cell_metrics",), + interactive_viewer=True, + viewer_cell_threshold=16, + run_card_display_builder=_atom_run_card_display, +) diff --git a/cvs/lib/report/types.py b/cvs/lib/report/types.py index 56bf0ae2a..4c3458a13 100644 --- a/cvs/lib/report/types.py +++ b/cvs/lib/report/types.py @@ -32,6 +32,7 @@ class ReportChartSeries: title: str unit: str invert: bool = False + metric_key: str = "" @dataclass(frozen=True) @@ -63,15 +64,15 @@ class InferenceReportConfig: interactive_viewer: bool = True viewer_cell_threshold: int = 24 prev_run_json: str = "" - run_card_display_builder: RunCardDisplayFn = field( - default=lambda _variant, _prov: [("Suite", "inference", False)] - ) + run_card_display_builder: RunCardDisplayFn = field(default=lambda _variant, _prov: [("Suite", "inference", False)]) @property def gated_tiers(self) -> tuple[str, ...]: return tuple(t for t in self.metric_tier_order if t != self.record_tier) def full_metric(self, short: str) -> str: + if "." in short: + return short if short.startswith(f"{self.metric_prefix}"): return short return f"{self.metric_prefix}{short}" diff --git a/cvs/tests/inference/inferencex_atom/conftest.py b/cvs/tests/inference/inferencex_atom/conftest.py index 08d77b795..b3dffb361 100644 --- a/cvs/tests/inference/inferencex_atom/conftest.py +++ b/cvs/tests/inference/inferencex_atom/conftest.py @@ -33,14 +33,22 @@ def _log_variant_run_card(variant_config): f"model={variant_config.model.id}", ] atom_args = variant_config.roles.server.atom_args + serve_args = variant_config.roles.server.serve_args if atom_args: parts.append(f"atom_args={len(atom_args)} tokens") + if serve_args: + parts.append(f"serve_args={len(serve_args)} keys") if rc.atom_image_pin: parts.append(f"image_pin={rc.atom_image_pin}") + if rc.vllm_image_pin: + parts.append(f"vllm_image_pin={rc.vllm_image_pin}") if rc.upstream_run_url: parts.append(f"upstream_run={rc.upstream_run_url}") if rc.notes: parts.append(f"notes={rc.notes}") + if int(variant_config.params.nnodes) > 1: + parts.append(f"nnodes={variant_config.params.nnodes}") + parts.append(f"pp={variant_config.params.pipeline_parallel_size}") log.info("InferenceX ATOM run card: %s", "; ".join(parts)) @@ -55,6 +63,7 @@ def _emit_variant_run_card(variant_config): "test_setup_sshd": 1, "test_model_fetch": 2, "test_inferencex_atom_inference": 3, + "test_inferencex_atom_vllm_inference": 3, "test_cell_metrics": 4, "test_print_results_table": 5, "test_teardown": 6, diff --git a/cvs/tests/inference/inferencex_atom/inferencex_atom_single.py b/cvs/tests/inference/inferencex_atom/inferencex_atom.py similarity index 86% rename from cvs/tests/inference/inferencex_atom/inferencex_atom_single.py rename to cvs/tests/inference/inferencex_atom/inferencex_atom.py index 3f1d92d2d..90bf4b9a7 100644 --- a/cvs/tests/inference/inferencex_atom/inferencex_atom_single.py +++ b/cvs/tests/inference/inferencex_atom/inferencex_atom.py @@ -12,10 +12,10 @@ from cvs.lib import globals from cvs.lib.inference.inference_suite_lifecycle import ( sweep_cell_result_key, - test_launch_container, - test_model_fetch, - test_setup_sshd, - test_teardown, + test_launch_container, # noqa: F401 + test_model_fetch, # noqa: F401 + test_setup_sshd, # noqa: F401 + test_teardown, # noqa: F401 ) from cvs.lib.inference.inferencex_atom_orch import InferenceXAtomJob from cvs.lib.inference.utils.inferencex_atom_config_loader import ( @@ -27,6 +27,7 @@ CLIENT_METRIC_UNITS as _METRIC_UNITS, METRIC_TIERS, RECORD_METRICS, + SCALING_METRIC_UNITS, tier_metric_specs, ) from cvs.lib.utils.verdict import evaluate_all @@ -45,9 +46,7 @@ def _tier_display_metric(tier): def pytest_generate_tests(metafunc): config_file = metafunc.config.getoption("config_file") if not config_file or not os.path.isfile(config_file): - raise pytest.UsageError( - f"--config_file not found or not specified: {config_file!r}" - ) + raise pytest.UsageError(f"--config_file not found or not specified: {config_file!r}") with open(config_file) as fp: raw = json.load(fp) spec = expand_sweep_parametrize(raw.get("sweep", {}), metafunc.fixturenames) @@ -140,21 +139,25 @@ def test_cell_metrics( specs = tier_metric_specs(thresholds_cell, metric_tier) display = _tier_display_metric(metric_tier) - full = f"client.{display}" + if metric_tier == "scaling": + full = f"scaling.{display}" + unit = SCALING_METRIC_UNITS.get(display, "%") + else: + full = f"client.{display}" + unit = _METRIC_UNITS.get(display, metric_tier) value = actuals.get(full) - unit = _METRIC_UNITS.get(display, metric_tier) request.node.user_properties.append(("metric_value", value)) request.node.user_properties.append(("metric_unit", unit)) if not variant_config.enforce_thresholds or metric_tier == "record": return if not specs: + if metric_tier == "scaling" and int(variant_config.params.nnodes) <= 1: + pytest.skip("scaling tier not configured for single-node runs") pytest.fail(f"no threshold specs for tier {metric_tier!r} in cell {cell!r}") # ATOM benchmark_serving may omit some tail percentiles even when # metric_percentiles requests them; only gate metrics present in actuals. - specs = { - k: v for k, v in specs.items() if k in actuals and actuals[k] is not None - } + specs = {k: v for k, v in specs.items() if k in actuals and actuals[k] is not None} if not specs: pytest.fail( f"no assertable threshold specs for tier {metric_tier!r} in cell {cell!r} " diff --git a/cvs/tests/inference/inferencex_atom/inferencex_atom_vllm.py b/cvs/tests/inference/inferencex_atom/inferencex_atom_vllm.py new file mode 100644 index 000000000..3be020a99 --- /dev/null +++ b/cvs/tests/inference/inferencex_atom/inferencex_atom_vllm.py @@ -0,0 +1,196 @@ +''' +Copyright 2025 Advanced Micro Devices, Inc. +All rights reserved. + +InferenceX vLLM parity suite (M4): same sweep layout as ``inferencex_atom`` +with ``framework: inferencex_atom_vllm_single`` and ``params.driver: vllm``. +''' + +import json +import os +import time + +import pytest + +from cvs.lib import globals +from cvs.lib.inference.inference_suite_lifecycle import ( + sweep_cell_result_key, + test_launch_container, + test_model_fetch, + test_setup_sshd, + test_teardown, +) +from cvs.lib.inference.inferencex_atom_orch import InferenceXAtomJob +from cvs.lib.inference.utils.inferencex_atom_config_loader import ( + expand_sweep_parametrize, + load_parity_reference_cells, + reuse_server_flag, + server_session_key, +) +from cvs.lib.inference.utils.inferencex_atom_parsing import ( + CLIENT_METRIC_UNITS as _METRIC_UNITS, + COMPARE_VLLM_METRIC_UNITS, + METRIC_TIERS, + RECORD_METRICS, + SCALING_METRIC_UNITS, + VLLM_METRIC_TIER_ORDER, + compare_vllm_metrics, + tier_metric_specs, +) +from cvs.lib.utils.verdict import evaluate_all +from cvs.tests.inference.inferencex_atom._shared import test_print_results_table # noqa: F401 + +log = globals.log + + +def _tier_display_metric(tier): + if tier == "record": + return RECORD_METRICS[0] if RECORD_METRICS else "output_throughput" + if tier == "compare": + from cvs.lib.inference.utils.inferencex_atom_parsing import COMPARE_VLLM_METRICS + + return COMPARE_VLLM_METRICS[0] + names = METRIC_TIERS.get(tier, ()) + return names[0] if names else tier + + +@pytest.fixture(scope="module") +def parity_reference_cells(variant_config): + path = (variant_config.run_card.parity_reference_json or "").strip() + if not path: + return {} + return load_parity_reference_cells(path) + + +def pytest_generate_tests(metafunc): + config_file = metafunc.config.getoption("config_file") + if not config_file or not os.path.isfile(config_file): + raise pytest.UsageError( + f"--config_file not found or not specified: {config_file!r}" + ) + with open(config_file) as fp: + raw = json.load(fp) + spec = expand_sweep_parametrize( + raw.get("sweep", {}), + metafunc.fixturenames, + metric_tier_order=VLLM_METRIC_TIER_ORDER, + ) + if spec: + argnames, argvalues, ids = spec + metafunc.parametrize(argnames, argvalues, ids=ids) + + +def test_inferencex_atom_vllm_inference( + orch, + variant_config, + hf_token, + seq_combo, + concurrency, + inf_res_dict, + server_session, + lifecycle, + parity_reference_cells, + request, +): + if lifecycle.failed: + pytest.skip("a prior lifecycle stage failed") + + isl = seq_combo["isl"] + osl = seq_combo["osl"] + p = variant_config.params + job = InferenceXAtomJob.from_variant( + orch=orch, + variant=variant_config, + hf_token=hf_token, + isl=isl, + osl=osl, + concurrency=concurrency, + ) + + session_key = server_session_key(variant_config, isl, osl) + reuse = reuse_server_flag(p) and server_session.get("key") == session_key + + try: + if not reuse: + job.stop_server() + job.build_server_cmd() + t = time.monotonic() + job.start_server() + job.wait_ready() + lifecycle.record(request.node.nodeid, "server_ready", time.monotonic() - t) + if reuse_server_flag(p): + server_session["key"] = session_key + else: + log.info("reusing vLLM server across sweep cell (key=%s)", session_key) + job.prepare_cell_out_dir() + t_client = time.monotonic() + job.run_client() + job.wait_client_complete() + results = job.parse_results() + except Exception: + lifecycle.failed = True + raise + + cell = variant_config.cell_key(isl, osl, concurrency) + ref_cell = parity_reference_cells.get(cell) + if ref_cell: + for host, metrics in results.items(): + metrics.update(compare_vllm_metrics(metrics, ref_cell)) + + inf_res_dict[sweep_cell_result_key(variant_config, seq_combo, isl, osl, concurrency)] = results + lifecycle.record(request.node.nodeid, "client_complete", time.monotonic() - t_client) + + +def test_cell_metrics( + seq_combo, + concurrency, + metric_tier, + inf_res_dict, + variant_config, + lifecycle, + request, +): + if lifecycle.failed: + pytest.skip("a prior lifecycle stage failed") + isl = seq_combo["isl"] + osl = seq_combo["osl"] + key = sweep_cell_result_key(variant_config, seq_combo, isl, osl, concurrency) + if key not in inf_res_dict: + pytest.skip(f"no recorded results for cell {key!r} (inference did not run)") + host_dict = inf_res_dict[key] + _host, actuals = next(iter(host_dict.items())) + cell = variant_config.cell_key(isl, osl, concurrency) + thresholds_cell = variant_config.thresholds.get(cell) or {} + specs = tier_metric_specs(thresholds_cell, metric_tier) + + display = _tier_display_metric(metric_tier) + if metric_tier == "scaling": + full = f"scaling.{display}" + unit = SCALING_METRIC_UNITS.get(display, "%") + elif metric_tier == "compare": + full = f"compare.vllm.{display}" + unit = COMPARE_VLLM_METRIC_UNITS.get(display, "ratio") + else: + full = f"client.{display}" + unit = _METRIC_UNITS.get(display, metric_tier) + value = actuals.get(full) + request.node.user_properties.append(("metric_value", value)) + request.node.user_properties.append(("metric_unit", unit)) + + if not variant_config.enforce_thresholds or metric_tier == "record": + return + if not specs: + if metric_tier == "scaling" and int(variant_config.params.nnodes) <= 1: + pytest.skip("scaling tier not configured for single-node runs") + if metric_tier == "compare" and not (variant_config.run_card.parity_reference_json or "").strip(): + pytest.skip("compare tier requires run_card.parity_reference_json") + pytest.fail(f"no threshold specs for tier {metric_tier!r} in cell {cell!r}") + specs = { + k: v for k, v in specs.items() if k in actuals and actuals[k] is not None + } + if not specs: + pytest.fail( + f"no assertable threshold specs for tier {metric_tier!r} in cell {cell!r} " + f"(metrics missing from benchmark artifact)" + ) + evaluate_all(actuals, specs) diff --git a/docs/how-to/run-cvs-tests.rst b/docs/how-to/run-cvs-tests.rst index c48ff7e21..5443f2941 100644 --- a/docs/how-to/run-cvs-tests.rst +++ b/docs/how-to/run-cvs-tests.rst @@ -42,7 +42,7 @@ You can list available tests using either `cvs run` (with no arguments) or `cvs • install_ibperf_tools cvs.tests.inference.inferencex_atom (1 test suite) - • inferencex_atom_single + • inferencex_atom cvs.tests.inference.pytorch_xdit (2 test suites) • pytorch_xdit_flux1_dev_single @@ -631,11 +631,11 @@ You can list all available InferenceX ATOM test cases using the CLI: .. code:: bash - cvs list inferencex_atom_single + cvs list inferencex_atom .. code:: text - Available tests in inferencex_atom_single: + Available tests in inferencex_atom: - test_launch_container - test_inferencex_atom_inference - test_print_results_table @@ -644,15 +644,15 @@ You can list all available InferenceX ATOM test cases using the CLI: Use these scripts to run the InferenceX ATOM tests. Supply your own suite JSON (``schema_version: 1`` variant config); see :doc:`../reference/configuration-files/inferencex_atom`. After ``cvs copy-config``, keep **one** ``*threshold.json`` in the same directory as the -``--config_file`` you pass (per-variant subdirs under ``~/input/.../inferencex_atom_single/``). -Copy-paste lab commands: ``cvs/input/config_file/inference/inferencex_atom_single/README.md``. +``--config_file`` you pass (per-variant subdirs under ``~/input/.../inferencex_atom/``). +Copy-paste lab commands: ``cvs/input/config_file/inference/inferencex_atom/README.md``. .. code:: bash TS=$(date +%Y%m%d_%H%M%S) - cvs run inferencex_atom_single \ + cvs run inferencex_atom \ --cluster_file ~/input/cluster_file/mi300x_atom_single.json \ - --config_file ~/input/config_file/inference/inferencex_atom_single/smoke/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json \ + --config_file ~/input/config_file/inference/inferencex_atom/smoke/mi300x_inferencex-atom-single_deepseek-r1_fp8_smoke_config.json \ --html=~/cvs_results/${TS}_ix-atom-smoke_mi300x.html \ --self-contained-html \ --log-file=~/cvs_results/${TS}_ix-atom-smoke_mi300x.log \ diff --git a/docs/install/cvs-install.rst b/docs/install/cvs-install.rst index a08de631f..f2d46ee0e 100644 --- a/docs/install/cvs-install.rst +++ b/docs/install/cvs-install.rst @@ -312,8 +312,8 @@ CVS provides comprehensive inference testing configurations for various LLM serv .. code:: bash - cvs copy-config inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json --output ~/my_inferencex_atom_config.json - cvs copy-config inference/inferencex_atom_single/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json --output ~/my_inferencex_atom_threshold.json + cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_config.json --output ~/my_inferencex_atom_config.json + cvs copy-config inference/inferencex_atom/mi300x_inferencex-atom-single_gpt-oss-120b_bf16_threshold.json --output ~/my_inferencex_atom_threshold.json 2. Edit the files and modify these parameters: diff --git a/docs/reference/configuration-files/inferencex_atom.rst b/docs/reference/configuration-files/inferencex_atom.rst index de64b4fcc..8d1ffa759 100644 --- a/docs/reference/configuration-files/inferencex_atom.rst +++ b/docs/reference/configuration-files/inferencex_atom.rst @@ -19,7 +19,7 @@ The suite checks: - **Result verification**: Tiered ``client.*`` thresholds when ``enforce_thresholds`` is true Configs use flat ``*_config.json`` + sibling ``*_threshold.json`` pairs under -``cvs/input/config_file/inference/inferencex_atom_single/``. Filename pattern: +``cvs/input/config_file/inference/inferencex_atom/``. Filename pattern: ``{gpu}_inferencex-atom-single_{model}_{precision}[_{mode}]_config.json``. Pass ``--config_file`` to the ``*_config.json``; :func:`cvs.lib.utils.config_loader.substitute_config` discovers the sole sibling ``*threshold.json`` in the **config file's parent directory** when @@ -28,10 +28,10 @@ loading fails with an ambiguous-threshold ``ValueError``. **Lab ``~/input`` layout:** the repo keeps every variant flat in one tree, but after ``cvs copy-config`` you should place each run's config + threshold pair in a dedicated -subdirectory (for example ``~/input/.../inferencex_atom_single/smoke/``) so only one +subdirectory (for example ``~/input/.../inferencex_atom/smoke/``) so only one threshold file sits beside the config you pass to ``--config_file``. Alternatively set ``"threshold_json"`` in the config to an explicit path. See the in-tree README at -``cvs/input/config_file/inference/inferencex_atom_single/README.md`` for copy-paste commands. +``cvs/input/config_file/inference/inferencex_atom/README.md`` for copy-paste commands. **Cluster file:** use ``cvs/input/cluster_file/mi300x_atom_single.json`` (or ``mi355x_atom_single.json``). Container ``name`` must match the variant (``inferencex_atom_mi300x`` / ``inferencex_atom_mi355x``); @@ -47,7 +47,7 @@ cluster nodes (``cluster_file`` ``mgmt_ip`` / ``node_dict``) and runs ``sudo doc ``roles.server.serve_args`` on ``vllm_single``). When ``params.driver`` is ``atom``, ``atom_args`` is required. MTP3 variants also set ``params.bench_extra_args`` (for example ``--use-chat-template``). -Pytest and HTML layout (inferencex_atom_single) +Pytest and HTML layout (inferencex_atom) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. list-table:: @@ -82,7 +82,7 @@ Pytest and HTML layout (inferencex_atom_single) Example variant layout ====================== -Each stem has ``_config.json`` (``schema_version: 1``, ``framework: inferencex_atom_single``) +Each stem has ``_config.json`` (``schema_version: 1``, ``framework: inferencex_atom``) and sibling ``_threshold.json``. In the CVS source tree many stems share one directory; on a lab machine, copy only the pair you need into a per-variant subdirectory (or set ``threshold_json``). See ``mi300x_inferencex-atom-single_deepseek-r1_fp8_perf_config.json`` @@ -120,7 +120,7 @@ Top-level blocks follow the DTNI variant schema. InferenceX ATOM-specific keys: - Example - Description * - ``framework`` - - ``inferencex_atom_single`` + - ``inferencex_atom`` - Suite identifier for :func:`load_variant`. * - ``gpu_arch`` - ``mi300x`` @@ -158,6 +158,15 @@ Top-level blocks follow the DTNI variant schema. InferenceX ATOM-specific keys: * - ``params.reuse_server_across_sweep`` - ``true`` - Skip server restart when only concurrency changes between sweep cells. + * - ``params.nnodes`` / ``params.pipeline_parallel_size`` + - ``2`` / ``2`` + - Multinode distributed serve (M5). Omit or set ``nnodes: "1"`` for single-node. + * - ``params.master_addr`` / ``params.master_port`` + - head VPC IP / ``29501`` + - Rendezvous for distributed ATOM/vLLM executor; defaults to cluster head when empty. + * - ``params.scaling_baseline_output_throughput`` + - ``1500`` + - Single-node reference ``output_throughput`` for ``scaling.efficiency_pct`` (record-only). * - ``params.server_warmup_wait_s`` / ``client_initial_wait_s`` - ``330`` / ``120`` - Config-driven server warmup and client poll floor (shorter on smoke configs).