diff --git a/jenkins/L0_Test.groovy b/jenkins/L0_Test.groovy index f3979dc4a989..2785d44dd3fa 100644 --- a/jenkins/L0_Test.groovy +++ b/jenkins/L0_Test.groovy @@ -895,19 +895,22 @@ def getMountListForSlurmTest(SlurmCluster cluster, boolean useSbatch = false) def runLLMTestlistWithSbatch(pipeline, platform, testList, config=VANILLA_CONFIG, perfMode=false, stageName="Undefined", splitId=1, splits=1, gpuCount=1, nodeCount=1, skipInstallWheel=false, cpver="cp312") { - SlurmPartition partition = SlurmConfig.partitionConfig[platform] as SlurmPartition + SlurmPartition partition = SlurmConfig.resolvePlatform(platform) SlurmCluster cluster = SlurmConfig.clusterConfig[partition.clusterName] // Create a unique suffix for the job name String customSuffix = "${env.BUILD_TAG}-${UUID.randomUUID().toString().replaceAll("-", "").substring(0, 6)}".toLowerCase() def jobUID = "${cluster.host}-multi_node_test-${customSuffix}" - def disaggMode = stageName.contains("PerfSanity-Disagg") + def disaggMode = stageName.contains("Disagg-PerfSanity") Utils.exec(pipeline, script: "env | sort && pwd && ls -alh") + def stageIsInterrupted = false + try { // Run ssh command to start node in desired cluster via SLURM withCredentials([ + string(credentialsId: 'TRTLLM_HF_TOKEN', variable: 'HF_TOKEN'), usernamePassword( credentialsId: 'svc_tensorrt', usernameVariable: 'USERNAME', @@ -1164,6 +1167,7 @@ def runLLMTestlistWithSbatch(pipeline, platform, testList, config=VANILLA_CONFIG export resourcePathNode=$resourcePathNode export pytestCommand="$pytestCommand" export coverageConfigFile="$coverageConfigFile" + export HF_TOKEN=$HF_TOKEN export NVIDIA_IMEX_CHANNELS=\${NVIDIA_IMEX_CHANNELS:-0} export NVIDIA_VISIBLE_DEVICES=\${NVIDIA_VISIBLE_DEVICES:-\$(seq -s, 0 \$((\$(nvidia-smi --query-gpu=count -i 0 --format=csv,noheader)-1)))} ${envExportStatements} @@ -1175,10 +1179,6 @@ def runLLMTestlistWithSbatch(pipeline, platform, testList, config=VANILLA_CONFIG """.replaceAll("(?m)^\\s*", "") if (disaggMode) { - if(nodeCount > 1) { - srunArgs.add("--mpi=pmix") - } - def scriptLaunchPrefixPathLocal = Utils.createTempLocation(pipeline, "./slurm_launch_prefix.sh") def scriptLaunchSrunArgsPathLocal = Utils.createTempLocation(pipeline, "./slurm_srun_args.txt") def scriptLaunchDraftPathLocal = "${llmSrcLocal}/jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh" @@ -1198,7 +1198,8 @@ def runLLMTestlistWithSbatch(pipeline, platform, testList, config=VANILLA_CONFIG --run-sh ${scriptRunPathNode} \\ --install-sh ${scriptInstallPathNode} \\ --script-prefix ${scriptLaunchPrefixPathLocal} \\ - --srun-args ${scriptLaunchSrunArgsPathLocal} + --srun-args ${scriptLaunchSrunArgsPathLocal} \\ + --split-group ${splitId} """ } else { if(nodeCount > 1) { @@ -1376,8 +1377,11 @@ def runLLMTestlistWithSbatch(pipeline, platform, testList, config=VANILLA_CONFIG } echo "Finished test stage execution." } + } catch (InterruptedException e) { + stageIsInterrupted = true + throw e } finally { - uploadResults(pipeline, cluster, jobUID, stageName) + uploadResults(pipeline, cluster, jobUID, stageName, stageIsInterrupted) stage("Clean Up Slurm Resource") { // Workaround to handle the interruption during clean up SLURM resources retry(3) { diff --git a/jenkins/scripts/open_search_db.py b/jenkins/scripts/open_search_db.py index d27557a1b207..e4ceedba8034 100644 --- a/jenkins/scripts/open_search_db.py +++ b/jenkins/scripts/open_search_db.py @@ -283,6 +283,78 @@ def queryFromOpenSearchDB(json_data, project) -> dict: ) return None + @staticmethod + def queryPerfDataFromOpenSearchDB(project_name, + must_clauses, + size=DEFAULT_QUERY_SIZE, + must_not_clauses=None): + """ + Query perf data from OpenSearchDB using must and must_not clauses. + + :param project_name: Name of the project. + :param must_clauses: List of must clauses for query. + :param size: Query size. + :param must_not_clauses: List of must_not clauses for query. + :return: list of data dicts, empty list if no data, None on error. + """ + if DISABLE_OPEN_SEARCH_DB_FOR_LOCAL_TEST: + return [] + if must_clauses is None: + must_clauses = [] + if must_not_clauses is None: + must_not_clauses = [] + if not isinstance(must_clauses, list): + OpenSearchDB.logger.info( + f"Invalid must_clauses type: {type(must_clauses).__name__}") + return None + if not isinstance(must_not_clauses, list): + OpenSearchDB.logger.info( + f"Invalid must_not_clauses type: {type(must_not_clauses).__name__}" + ) + return None + + bool_query = {"must": must_clauses} + if must_not_clauses: + bool_query["must_not"] = must_not_clauses + + json_data = { + "query": { + "bool": bool_query + }, + "size": size, + } + + data_list = [] + try: + res = OpenSearchDB.queryFromOpenSearchDB(json_data, project_name) + if res is None: + OpenSearchDB.logger.info( + f"Failed to query from {project_name}, returned no response" + ) + return None + payload = res.json().get("hits", {}).get("hits", []) + if len(payload) == 0: + OpenSearchDB.logger.info( + f"No data found in {project_name}, returned empty list") + return [] + for hit in payload: + data_dict = hit.get("_source", {}) + data_dict["_id"] = hit.get("_id", "") + if data_dict["_id"] == "": + OpenSearchDB.logger.info( + f"Failed to query from {project_name}, returned data with no _id" + ) + return None + data_list.append(data_dict) + OpenSearchDB.logger.info( + f"Successfully queried from {project_name}, queried {len(data_list)} entries" + ) + return data_list + except Exception as e: + OpenSearchDB.logger.warning( + f"Failed to query from {project_name}, returned error: {e}") + return None + @staticmethod def queryBuildIdFromOpenSearchDB(job_name, last_days=DEFAULT_LOOKBACK_DAYS): if DISABLE_OPEN_SEARCH_DB_FOR_LOCAL_TEST: diff --git a/jenkins/scripts/perf/README.md b/jenkins/scripts/perf/README.md new file mode 100644 index 000000000000..4cae9811c080 --- /dev/null +++ b/jenkins/scripts/perf/README.md @@ -0,0 +1,182 @@ +# Perf Sanity Scripts + +This directory contains scripts for running perf sanity tests and managing perf sanity data. + +## Directory Structure + +``` +jenkins/scripts/perf/ + aggregated/ + slurm_launch_draft.sh # Draft template for aggregated SLURM launch scripts + disaggregated/ + submit.py # CI pipeline submit script (disaggregated only) + slurm_launch_draft.sh # Draft template for disaggregated SLURM launch scripts + local/ + submit.py # Local submit script (aggregated and disaggregated) + slurm_install.sh # Build wheel + pip install inside container + slurm_run.sh # Run pytest inside container + perf_utils.py # Shared utilities (regression detection, baseline, charts, OpenSearch queries) + get_pre_merge_html.py # Pre-merge HTML report with history, baseline, and threshold + perf_sanity_triage.py # Query/update OpenSearch data and send Slack notifications +``` + +## Submit Scripts + +Both `local/submit.py` and `disaggregated/submit.py` share a similar workflow. They read +a test config YAML and use the appropriate draft template +(`aggregated/slurm_launch_draft.sh` or `disaggregated/slurm_launch_draft.sh`) to generate +a complete `slurm_launch.sh`. Then the user or CI pipeline can run `sbatch slurm_launch.sh` +to submit the job. Inside the SLURM job, `slurm_install.sh` builds the wheel and runs +installation, then `slurm_run.sh` runs pytest. + +``` +submit.py + | + v +slurm_launch.sh (generated) + | + |-- srun --> slurm_install.sh (build wheel + pip install) + |-- srun --> slurm_run.sh (run pytest) +``` + +Both submit scripts read `AGG_CONFIG_FOLDER` and `DISAGG_CONFIG_FOLDER` environment +variables (with defaults of `tests/scripts/perf-sanity/aggregated` and +`tests/scripts/perf-sanity/disaggregated`) and propagate them via `PYTEST_COMMON_VARS` +into the pytest execution environment where `test_perf_sanity.py` uses them to locate +config files. + +### `local/submit.py` + +Used for **local runs**. Supports both **aggregated** and **disaggregated** modes. It +detects the mode from the test config YAML (aggregated configs have `server_configs`, +disaggregated configs have `worker_config`) and selects the correct draft template +automatically. + +See [`local/README.md`](local/README.md) for full argument reference and examples. + +### `disaggregated/submit.py` + +Used by the **CI pipeline** (called from `jenkins/L0_Test.groovy`'s +`runLLMTestlistWithSbatch`). Only supports **disaggregated** mode. It receives a +script prefix and srun args from the CI pipeline and combines them with disagg-specific +environment variables and hardware configuration to generate `slurm_launch.sh`. + +## Shared Utilities + +### `perf_utils.py` + +Shared module imported by `get_post_merge_html.py`, `get_pre_merge_html.py`, and +`perf_sanity_triage.py`. Contains: + +- **Constants**: `CHART_METRICS` (4 key throughput metrics), `METRIC_LABELS`, + algorithm parameters, curve type colors/labels. +- **Baseline computation**: Rolling smooth (window=3) + P95 percentile algorithm. + Replaces the previous `max(daily_values)` approach which was vulnerable to + occasional spikes inflating the baseline. +- **Regression detection**: Two-step classification (regression check + subtype + pattern matching). Supports per-metric thresholds from baseline data + (`d_threshold_pre_merge_*` fields, defaulting to 5%). +- **OpenSearch query + grouping**: `get_history_data()` queries both baseline and + non-baseline data, groups by `(s_test_case_name, s_gpu_type)`. +- **SVG chart generation**: Unified chart function supporting history lines, + new data points, baseline line, threshold line, curve type badges, and jump + interval shading. +- **HTML dashboard**: `generate_post_merge_html()` produces a full interactive + report with three-way cascading filters and click-to-inspect data-point popups. + +## MPI/PMI Handling in Disaggregated Tests + +### Background + +Disaggregated tests run four srun steps within a single SLURM job. Only CTX/GEN workers +need MPI (they use `trtllm-llmapi-launch`). The disagg server (`trtllm-serve +disaggregated`) and benchmark client are single-process, non-MPI tasks. + +When srun launches a process with `--mpi=pmix`, it sets PMI/PMIx environment variables. +If the launched process imports libraries with MPI support (e.g., PyTorch links Open MPI), +`MPI_Init` may be triggered automatically. If the container's MPI build lacks SLURM PMI +support, this causes: +``` +PMI2_Init failed to initialize. Return code: 14 +``` + +### Solution + +The `--mpi=pmix` flag is added **only** to the CTX/GEN worker srun commands in +`slurm_launch_draft.sh`, not to the shared `srunArgs` array. This way, the disagg server +and benchmark srun steps never see MPI flags. + +**Where MPI is configured:** +- `jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh` — `--mpi=pmix` on + ctx/gen srun commands only +- `jenkins/scripts/perf/local/submit.py` — `--mpi=pmi2` for aggregated mode only, + no MPI flag for disaggregated mode (handled by the draft template) +- `jenkins/L0_Test.groovy` — `--mpi=pmi2` for non-disagg multi-node only + +### Key Rules + +When modifying disaggregated SLURM scripts, keep these invariants: + +1. **srunArgs are shared**: All srun steps in `slurm_launch_draft.sh` use the same + `"${srunArgs[@]}"`. Never add MPI flags to srunArgs for disaggregated mode. +2. **Only CTX/GEN workers need MPI**: Add `--mpi=pmix` directly on their srun command + lines in `slurm_launch_draft.sh`, not in the shared srunArgs. +3. **Non-MPI roles must stay MPI-free**: The disagg server and benchmark steps must + not receive `--mpi` flags. If adding a new srun step, consider whether it needs MPI. + +## Post-Processing and Triage + +### `get_pre_merge_html.py` + +Triggered at the end of the CI pipeline in `jenkins/L0_MergeRequest.groovy`. It has +3 main functions: + +1. **`load_perf_data`**: Reads perf_data.yaml files produced by test stages and + gathers all new perf data together. +2. **`get_pre_merge_history_data`**: Queries OpenSearch for post-merge history data + (both baseline and non-baseline), grouped by `(s_test_case_name, s_gpu_type)`. +3. **`generate_pre_merge_html`**: Generates an HTML report visualizing each test + case's key metrics (`d_seq_throughput`, `d_token_throughput`, + `d_total_token_throughput`, `d_user_throughput`) with history curve, new data + points, baseline line, and threshold line for regression comparison. + +### `perf_sanity_triage.py` + +Triggered by `jenkins/runPerfSanityTriage.groovy`. It supports two operations: + +1. **`SLACK BOT SENDS MESSAGE`**: Runs the perf-regression-detector pipeline + (`get_history_data` -> `get_baseline` -> `classify_test_case` -> + `generate_post_merge_html`), then sends the generated HTML dashboard to a + Slack channel. + +2. **`UPDATE SET ... (WHERE ...)`**: Updates fields on existing perf records that match + a query scope and posts the updated documents back to OpenSearch. + +**Examples** + +``` +SLACK BOT SENDS MESSAGE +``` + +``` +UPDATE SET b_is_valid=false WHERE s_test_case_name='test1' +UPDATE SET b_is_valid=false WHERE ts_created <= 'Feb 18, 2026 @ 22:32:02.960' AND s_test_case_name='test1' +``` + +See the `UPDATE` operation section below for supported operators and date formats. + +#### UPDATE Operators + +- SET clause: Only `=` is supported. +- WHERE clause: Supports `=`, `!=`, `>`, `<`, `>=`, `<=` operators. +- `=` and `!=` operators are allowed for all fields. +- `>`, `<`, `>=`, `<=` operators are only allowed for `ts_created` field (timestamp) or fields starting with `d_` (double type) or `l_` (integer type). + +#### `ts_created` Date Formats + +The `ts_created` field accepts date strings in the following formats: +- `'Feb 18, 2026 @ 22:32:02.960'` (with milliseconds) +- `'Feb 18, 2026 @ 22:32:02'` (without milliseconds) +- `'2026/02/18'` (date only) + +All date strings are interpreted as UTC for consistent timestamp conversion. diff --git a/jenkins/scripts/perf/aggregated/slurm_launch_draft.sh b/jenkins/scripts/perf/aggregated/slurm_launch_draft.sh new file mode 100644 index 000000000000..278d6ec7dfd5 --- /dev/null +++ b/jenkins/scripts/perf/aggregated/slurm_launch_draft.sh @@ -0,0 +1,23 @@ + +cleanup_on_failure() { + echo "Error: $1" + scancel ${SLURM_JOB_ID} + exit 1 +} + +mkdir -p $jobWorkspace +chmod +x $runScript + +# Run aggregated test +echo "Starting aggregated test..." +world_size=$((totalNodes * gpusPerNodePerServer)) +if ! srun "${srunArgs[@]}" --kill-on-bad-exit=1 \ + -N $totalNodes \ + --ntasks=$world_size \ + --ntasks-per-node=$gpusPerNodePerServer \ + $runScript; then + cleanup_on_failure "Aggregated test failed. Check logs in ${jobWorkspace} for details" +fi + +echo "Aggregated test completed successfully" +echo "Total runtime: $SECONDS seconds" diff --git a/jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh b/jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh index c5dc80c971a2..01660c230076 100644 --- a/jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh +++ b/jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh @@ -19,33 +19,33 @@ echo "Installation completed on all nodes" # Start gen servers echo "Starting gen servers..." for i in $(seq 0 $((numGenServers - 1))); do - gen_world_size=$((nodesPerGenServer * gpusPerNode)) + gen_world_size=$((nodesPerGenServer * gpusPerNodePerGenServer)) export DISAGG_SERVING_TYPE="GEN_$i" - export pytestCommand="$pytestCommandWorker" - srun "${srunArgs[@]}" --kill-on-bad-exit=1 \ + export pytestCommand="$pytestCommandGENWorker" + srun "${srunArgs[@]}" --mpi=pmix --kill-on-bad-exit=1 \ -N $nodesPerGenServer \ --ntasks=$gen_world_size \ - --ntasks-per-node=$gpusPerNode \ + --ntasks-per-node=$gpusPerNodePerGenServer \ $runScript &> $jobWorkspace/gen_server_$i.log & echo "Started gen server $i" done -# Start ctx servers (skip if gen_only mode) +# Start ctx servers (skip if gen_only_no_context mode) if [ "${TRTLLM_DISAGG_BENCHMARK_GEN_ONLY:-0}" != "1" ]; then echo "Starting ctx servers..." for i in $(seq 0 $((numCtxServers - 1))); do - ctx_world_size=$((nodesPerCtxServer * gpusPerNode)) + ctx_world_size=$((nodesPerCtxServer * gpusPerNodePerCtxServer)) export DISAGG_SERVING_TYPE="CTX_$i" - export pytestCommand="$pytestCommandWorker" - srun "${srunArgs[@]}" --kill-on-bad-exit=1 \ + export pytestCommand="$pytestCommandCTXWorker" + srun "${srunArgs[@]}" --mpi=pmix --kill-on-bad-exit=1 \ -N $nodesPerCtxServer \ - --ntasks=$ctx_world_size \ - --ntasks-per-node=$gpusPerNode \ + --ntasks=$ctx_world_size \ + --ntasks-per-node=$gpusPerNodePerCtxServer \ $runScript &> $jobWorkspace/ctx_server_$i.log & echo "Started ctx server $i" done else - echo "Skipping ctx servers (gen_only mode)" + echo "Skipping ctx servers (gen_only_no_context mode)" fi diff --git a/jenkins/scripts/perf/disaggregated/submit.py b/jenkins/scripts/perf/disaggregated/submit.py index 5e8e374f4f08..6962fa2c4e05 100644 --- a/jenkins/scripts/perf/disaggregated/submit.py +++ b/jenkins/scripts/perf/disaggregated/submit.py @@ -4,12 +4,17 @@ import yaml +AGG_CONFIG_FOLDER = "tests/scripts/perf-sanity/aggregated" +DISAGG_CONFIG_FOLDER = "tests/scripts/perf-sanity/disaggregated" + def get_hardware_config(config, benchmark_mode): hardware = config.get("hardware", {}) worker_config = config.get("worker_config", {}) - num_ctx_servers = 0 if "gen_only" in benchmark_mode else hardware.get("num_ctx_servers") + num_ctx_servers = ( + 0 if "gen_only_no_context" in benchmark_mode else hardware.get("num_ctx_servers") + ) num_gen_servers = hardware.get("num_gen_servers") gpus_per_node = hardware.get("gpus_per_node") @@ -38,6 +43,9 @@ def get_hardware_config(config, benchmark_mode): nodes_per_ctx_server = (gpus_per_ctx_server + gpus_per_node - 1) // gpus_per_node nodes_per_gen_server = (gpus_per_gen_server + gpus_per_node - 1) // gpus_per_node + gpus_per_node_per_ctx_server = min(gpus_per_ctx_server, gpus_per_node) + gpus_per_node_per_gen_server = min(gpus_per_gen_server, gpus_per_node) + total_nodes = num_ctx_servers * nodes_per_ctx_server + num_gen_servers * nodes_per_gen_server total_gpus = total_nodes * gpus_per_node @@ -49,6 +57,8 @@ def get_hardware_config(config, benchmark_mode): "gpus_per_gen_server": gpus_per_gen_server, "nodes_per_ctx_server": nodes_per_ctx_server, "nodes_per_gen_server": nodes_per_gen_server, + "gpus_per_node_per_ctx_server": gpus_per_node_per_ctx_server, + "gpus_per_node_per_gen_server": gpus_per_node_per_gen_server, "total_nodes": total_nodes, "total_gpus": total_gpus, } @@ -88,12 +98,10 @@ def get_env_config(config): def get_benchmark_config(config): benchmark = config.get("benchmark", {}) - mode = benchmark.get("mode", "e2e") concurrency_str = benchmark.get("concurrency_list", "1") concurrency = int(concurrency_str) if isinstance(concurrency_str, str) else concurrency_str return { - "mode": mode, "concurrency": concurrency, } @@ -102,7 +110,14 @@ def remove_whitespace_lines(lines): return [line.strip() for line in lines if line.strip()] -def get_pytest_command_no_llmapilaunch(script_prefix_lines): +def get_pytest_commands(script_prefix_lines): + # Get worker, disagg_server, benchmark pytest commands from pytest command. + # Worker pytest command is pytest command with trtllm-llmapi-launch and + # without --csv, --cov, --periodic flags. + # Disagg_server pytest command is pytest command without trtllm-llmapi-launch + # and without --csv, --cov, --periodic flags. + # Benchmark pytest command is pytest command without trtllm-llmapi-launch + # and with --csv, --cov, --periodic flags. pytest_command_line = None for line in script_prefix_lines: if "export pytestCommand=" in line: @@ -110,22 +125,132 @@ def get_pytest_command_no_llmapilaunch(script_prefix_lines): break if not pytest_command_line: - return "" + return "", "", "" + + def split_pytest_command_line(command_line): + # After pytest, there are six types of substrings: + # Type 1: --xxx=yyy (long option with value, self-contained) + # Type 2: --xxx= (long option with empty value, self-contained) + # Type 3: --xxx (long option flag, no value) + # Type 4: --xxx yyy (long option with value as next arg) + # Type 5: -x yyy (short single-letter option with value as next arg) + # Type 6: -x (short option flag, e.g., -v, -vv) + parts = command_line.split() + pytest_index = None + for idx, part in enumerate(parts): + if "pytest" == part: + pytest_index = idx + break + if pytest_index is None: + return parts + + grouped_parts = parts[: pytest_index + 1] + i = pytest_index + 1 + while i < len(parts): + part = parts[i] + has_next = i + 1 < len(parts) + next_is_value = has_next and not parts[i + 1].startswith("-") + + # Type 1 & 2: --xxx=yyy or --xxx= (self-contained, has '=') + if part.startswith("--") and "=" in part: + grouped_parts.append(part) + i += 1 + continue + + # Type 4: --xxx yyy (long option with value as next arg) + if part.startswith("--") and next_is_value: + grouped_parts.append(f"{part} {parts[i + 1]}") + i += 2 + continue + + # Type 3: --xxx (long option flag) + if part.startswith("--"): + grouped_parts.append(part) + i += 1 + continue + + # Type 5: -x yyy (short single-letter option with value as next arg) + # Only single letter after dash, e.g., -o, not -vv + if part.startswith("-") and len(part) == 2 and next_is_value: + grouped_parts.append(f"{part} {parts[i + 1]}") + i += 2 + continue + + # Type 6: -x (short option flag, including combined like -vv) + if part.startswith("-"): + grouped_parts.append(part) + i += 1 + continue + + # Other parts (shouldn't happen after pytest, but handle gracefully) + grouped_parts.append(part) + i += 1 + + return grouped_parts + + def is_llmapi_launch(part): + return "trtllm-llmapi-launch" in part + + def is_output_file_part(part): + return any(flag in part for flag in ("--csv", "--cov", "--periodic")) + + worker_line = pytest_command_line.replace("pytestCommand", "partialPytestCommandWorker") + worker_parts = [ + part for part in split_pytest_command_line(worker_line) if not is_output_file_part(part) + ] + worker_pytest_command = " ".join(worker_parts) - # Replace pytestCommand with pytestCommandNoLLMAPILaunch - replaced_line = pytest_command_line.replace("pytestCommand", "pytestCommandNoLLMAPILaunch") + disagg_server_line = pytest_command_line.replace( + "pytestCommand", "partialPytestCommandDisaggServer" + ) + disagg_server_parts = [ + part + for part in split_pytest_command_line(disagg_server_line) + if not is_llmapi_launch(part) and not is_output_file_part(part) + ] + disagg_server_pytest_command = " ".join(disagg_server_parts) - # Split by space, find and remove the substring with trtllm-llmapi-launch - replaced_line_parts = replaced_line.split() - replaced_line_parts_no_llmapi = [ - part for part in replaced_line_parts if "trtllm-llmapi-launch" not in part + benchmark_line = pytest_command_line.replace("pytestCommand", "partialPytestCommandBenchmark") + benchmark_parts = [ + part for part in split_pytest_command_line(benchmark_line) if not is_llmapi_launch(part) ] - return " ".join(replaced_line_parts_no_llmapi) + benchmark_pytest_command = " ".join(benchmark_parts) + + return ( + worker_pytest_command, + disagg_server_pytest_command, + benchmark_pytest_command, + ) -def get_config_yaml(test_list_path, llm_src): +def parse_test_case_name(test_list_path, llm_src, split_group=0): + """Parse test list to get config yaml path and benchmark mode. + + Test formats for disagg: + - Disagg e2e: disagg_upload-e2e-{config_base} + - Disagg gen_only: disagg_upload-gen_only-{config_base} + + Args: + test_list_path: Path to the test list file. + llm_src: Path to the LLM source code. + split_group: 1-indexed split group id. When > 0, selects the + split_group-th test from the list instead of the first one. + + Returns: + tuple: (config_yaml_path, benchmark_mode) + - benchmark_mode: "e2e" or "gen_only" + """ with open(test_list_path, "r") as f: - first_line = f.readline().strip() + lines = [line.strip() for line in f if line.strip()] + + if split_group > 0: + if split_group > len(lines): + raise ValueError( + f"split_group {split_group} exceeds number of tests in test list ({len(lines)})" + ) + first_line = lines[split_group - 1] + else: + first_line = lines[0] if "[" not in first_line or "]" not in first_line: raise ValueError( @@ -133,32 +258,33 @@ def get_config_yaml(test_list_path, llm_src): ) bracket_content = first_line.split("[")[-1].split("]")[0] parts = bracket_content.split("-") - if len(parts) < 2: + + if len(parts) < 3: raise ValueError( - f"Invalid test name format. Expected format: prefix-config_name, got: {bracket_content}" + f"Invalid disagg test format. Expected: disagg-{{mode}}-{{config}}, " + f"got: {bracket_content}" ) - # parts[0] is the prefix, parts[1:] is the config name + # parts[0] is the prefix, parts[1] is benchmark_mode, parts[2:] is the config name if "disagg" not in parts[0]: raise ValueError( - f"Invalid test name format. Expected format: disagg-config_name, got: {bracket_content}" + f"Invalid test name format. Expected format: disagg-mode-config_name, " + f"got: {bracket_content}" ) - config_base_name = "-".join(parts[1:]) - config_yaml_path = os.path.join( - llm_src, - "tests", - "integration", - "defs", - "perf", - "disagg", - "test_configs", - "disagg", - "perf", - f"{config_base_name}.yaml", - ) + + benchmark_mode = parts[1] # e2e or gen_only + if benchmark_mode not in ("e2e", "gen_only"): + raise ValueError( + f"Invalid benchmark_mode for disagg: {benchmark_mode}. Expected 'e2e' or 'gen_only'." + ) + + config_base_name = "-".join(parts[2:]) + config_yaml_path = os.path.join(llm_src, DISAGG_CONFIG_FOLDER, f"{config_base_name}.yaml") + if not os.path.exists(config_yaml_path): raise FileNotFoundError(f"Config file not found: {config_yaml_path}") - return config_yaml_path + + return config_yaml_path, benchmark_mode def main(): @@ -193,10 +319,18 @@ def main(): default="", help="Path to file containing srun args (optional, CI mode only)", ) + parser.add_argument( + "--split-group", + type=int, + default=0, + help="1-indexed split group id. Selects the N-th test from the test list.", + ) args = parser.parse_args() - config_yaml = get_config_yaml(args.test_list, args.llm_src) + config_yaml, benchmark_mode = parse_test_case_name( + args.test_list, args.llm_src, args.split_group + ) with open(config_yaml, "r") as f: config = yaml.safe_load(f) @@ -209,7 +343,6 @@ def main(): benchmark_config = get_benchmark_config(config) print(f"Benchmark configuration: {benchmark_config}") - benchmark_mode = benchmark_config["mode"] hardware_config = get_hardware_config(config, benchmark_mode) print(f"Hardware configuration: {hardware_config}") @@ -225,31 +358,57 @@ def main(): srun_args_lines = srun_args_content.split() - # Extract pytestCommand and generate pytestCommandNoLLMAPILaunch - pytest_command_no_llmapi_launch = get_pytest_command_no_llmapilaunch(script_prefix_lines) - - # Build worker env vars, add extra env vars for gen_only mode - worker_env_vars = env_config["worker_env_var"] + # Extract pytestCommand and generate partial pytest commands + ( + worker_pytest_command, + disagg_server_pytest_command, + benchmark_pytest_command, + ) = get_pytest_commands(script_prefix_lines) + + # Build worker env vars (split into ctx and gen for role-specific settings) + base_worker_env_vars = ( + f"FLASHINFER_JIT_DIR=/tmp/flashinfer_jit_cache_\\${{SLURM_LOCALID}} " + f"HF_HOME=/tmp/hf_home " + f"{env_config['worker_env_var']}" + ) + ctx_worker_env_vars = base_worker_env_vars + gen_worker_env_vars = base_worker_env_vars server_env_vars = env_config["server_env_var"] - if "gen_only" in benchmark_config["mode"]: - concurrency = benchmark_config["concurrency"] - worker_env_vars = ( - "TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1 " - f"TRTLLM_DISABLE_KV_CACHE_TRANSFER_OVERLAP=1 " - f"TLLM_BENCHMARK_REQ_QUEUES_SIZE={concurrency} {worker_env_vars}" - ) + # Handle gen only mode + if "gen_only_no_context" in benchmark_mode: + gen_worker_env_vars = f"TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1 {gen_worker_env_vars}" server_env_vars = f"TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1 {server_env_vars}" script_prefix_lines.append("export TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1") srun_args_lines.append("--container-env=TRTLLM_DISAGG_BENCHMARK_GEN_ONLY") + elif "gen_only" in benchmark_mode: + concurrency = benchmark_config.get("concurrency", 1) + ctx_worker_env_vars = f"TRTLLM_DISABLE_KV_CACHE_TRANSFER_OVERLAP=1 {ctx_worker_env_vars}" + gen_worker_env_vars = ( + f"TRTLLM_DISABLE_KV_CACHE_TRANSFER_OVERLAP=1 " + f"TLLM_BENCHMARK_REQ_QUEUES_SIZE={concurrency} {gen_worker_env_vars}" + ) + + pytest_common_vars = "" script_prefix_lines.extend( [ - pytest_command_no_llmapi_launch, - f'export pytestCommandWorker="unset UCX_TLS && {worker_env_vars} $pytestCommand"', - f'export pytestCommandDisaggServer="{server_env_vars} $pytestCommandNoLLMAPILaunch"', - f'export pytestCommandBenchmark="{env_config["benchmark_env_var"]} $pytestCommandNoLLMAPILaunch"', + worker_pytest_command, + disagg_server_pytest_command, + benchmark_pytest_command, + f'export PYTEST_COMMON_VARS="{pytest_common_vars}"', + f'export CTX_WORKER_ENV_VARS="{ctx_worker_env_vars}"', + f'export GEN_WORKER_ENV_VARS="{gen_worker_env_vars}"', + f'export SERVER_ENV_VARS="{server_env_vars}"', + f'export BENCHMARK_ENV_VARS="{env_config["benchmark_env_var"]}"', + 'export pytestCommandCTXWorker="unset UCX_TLS && $CTX_WORKER_ENV_VARS' + ' $PYTEST_COMMON_VARS $partialPytestCommandWorker"', + 'export pytestCommandGENWorker="unset UCX_TLS && $GEN_WORKER_ENV_VARS' + ' $PYTEST_COMMON_VARS $partialPytestCommandWorker"', + 'export pytestCommandDisaggServer="$SERVER_ENV_VARS $PYTEST_COMMON_VARS $partialPytestCommandDisaggServer"', + 'export pytestCommandBenchmark="$BENCHMARK_ENV_VARS $PYTEST_COMMON_VARS $partialPytestCommandBenchmark"', f"export runScript={args.run_sh}", f"export installScript={install_script}", + f"export configYamlPath={config_yaml}", f"export numCtxServers={hardware_config['num_ctx_servers']}", f"export numGenServers={hardware_config['num_gen_servers']}", f"export gpusPerNode={hardware_config['gpus_per_node']}", @@ -257,6 +416,8 @@ def main(): f"export gpusPerGenServer={hardware_config['gpus_per_gen_server']}", f"export nodesPerCtxServer={hardware_config['nodes_per_ctx_server']}", f"export nodesPerGenServer={hardware_config['nodes_per_gen_server']}", + f"export gpusPerNodePerCtxServer={hardware_config['gpus_per_node_per_ctx_server']}", + f"export gpusPerNodePerGenServer={hardware_config['gpus_per_node_per_gen_server']}", f"export totalNodes={hardware_config['total_nodes']}", f"export totalGpus={hardware_config['total_gpus']}", ] diff --git a/jenkins/scripts/perf/get_pre_merge_html.py b/jenkins/scripts/perf/get_pre_merge_html.py new file mode 100644 index 000000000000..927675b54e86 --- /dev/null +++ b/jenkins/scripts/perf/get_pre_merge_html.py @@ -0,0 +1,276 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Generate a pre-merge HTML report with inline SVG performance charts. + +Reads perf_data.yaml files produced by test stages, queries OpenSearch for +historical data and baselines, then generates an HTML report visualizing +key throughput metrics with history, new data, baseline, and threshold lines +for regression comparison. +""" + +import argparse +import os +from html import escape as escape_html + +import yaml + +# Set OPEN_SEARCH_DB_BASE_URL before importing perf_utils, because +# open_search_db captures the env var at module-import time. +if not os.environ.get("OPEN_SEARCH_DB_BASE_URL"): + os.environ["OPEN_SEARCH_DB_BASE_URL"] = "http://gpuwa.nvidia.com" + +from perf_utils import ( + CHART_METRICS, + METRIC_LABELS, + _extract_points, + _generate_svg_chart, + _get_threshold_for_metric, + _ts_to_date, + get_history_data, +) + +# --------------------------------------------------------------------------- +# Data gathering +# --------------------------------------------------------------------------- + + +def load_perf_data(input_files): + """Read comma-separated perf_data.yaml paths and return a flat list of new_data dicts.""" + yaml_files = [f.strip() for f in input_files.split(",") if f.strip()] + all_new_data = [] + load_failures = 0 + for yaml_file in yaml_files: + try: + with open(yaml_file, "r", encoding="utf-8") as f: + content = yaml.safe_load(f) + if content is None or not isinstance(content, list): + continue + for e in content: + if not isinstance(e, dict): + continue + nd = e.get("new_data") + if isinstance(nd, dict) and "s_test_case_name" in nd: + all_new_data.append(nd) + except (OSError, yaml.YAMLError, UnicodeDecodeError) as exc: + load_failures += 1 + print(f"Warning: Failed to load {yaml_file}: {exc}") + if yaml_files and not all_new_data and load_failures == len(yaml_files): + raise RuntimeError("Failed to load any perf data YAML inputs; cannot generate report.") + return all_new_data + + +# --------------------------------------------------------------------------- +# History data query +# --------------------------------------------------------------------------- + + +def get_pre_merge_history_data(new_data_list): + """Query OpenSearch for history data matching test cases in *new_data_list*. + + Uses :func:`perf_utils.get_history_data` to fetch post-merge history + (both baseline and non-baseline), then filters to only the + (s_test_case_name, s_gpu_type) pairs present in *new_data_list*. + + Returns: + dict mapping (test_case, gpu_type) -> { + "history_data": [...], + "baseline_data": [...], + } + or empty dict on failure / no matches. + """ + if not new_data_list: + return {} + + # Determine which test case keys are present in new data + needed_keys = set() + for nd in new_data_list: + key = (nd.get("s_test_case_name", ""), nd.get("s_gpu_type", "")) + needed_keys.add(key) + + grouped = get_history_data( + extra_must_clauses=[ + {"term": {"b_is_post_merge": True}}, + {"term": {"s_branch": "main"}}, + ] + ) + + if grouped is None: + print("Warning: Failed to query history data from OpenSearch") + return {} + + # Filter to only the test cases we have new data for + filtered = {} + for key, bucket in grouped.items(): + if key in needed_keys: + filtered[key] = bucket + + return filtered + + +# --------------------------------------------------------------------------- +# HTML report generation +# --------------------------------------------------------------------------- + + +def _extract_simple_points(data_list, metric): + """Extract (datetime, float_value) pairs from a list of data dicts.""" + points = [] + for d in data_list: + ts = d.get("ts_created") or d.get("@timestamp") + val = d.get(metric) + if ts is not None and val is not None: + try: + points.append((_ts_to_date(ts), float(val))) + except (ValueError, TypeError): + pass + points.sort(key=lambda p: p[0]) + return points + + +def generate_pre_merge_html(new_data_list, history_grouped, output_file): + """Generate HTML report visualizing new data against history + baseline. + + For each (test_case, gpu_type) present in *new_data_list*, renders 4 + charts (one per key metric) showing history line, new data points, + baseline line, and threshold line for regression comparison. + """ + # Group new data by (test_case, gpu_type) + new_groups = {} + for nd in new_data_list: + key = (nd.get("s_test_case_name", ""), nd.get("s_gpu_type", "")) + new_groups.setdefault(key, []).append(nd) + + sections_html = [] + for (test_case, gpu_type), new_data_entries in sorted(new_groups.items()): + bucket = history_grouped.get((test_case, gpu_type), {}) + history_data = bucket.get("history_data", []) + baseline_data_list = bucket.get("baseline_data", []) + + charts = [] + for metric in CHART_METRICS: + label = METRIC_LABELS.get(metric, metric) + + # History points (blue line) — use 3-tuple version from perf_utils + hist_pts = _extract_points(history_data, metric) + + # New data points (red dots) + new_pts = _extract_simple_points(new_data_entries, metric) + + # Baseline value from the latest baseline entry + baseline_value = None + if baseline_data_list: + latest_bl = baseline_data_list[-1] + bl_val = latest_bl.get(metric) + if bl_val is not None: + baseline_value = float(bl_val) + + # Threshold line value + threshold_line_value = None + if baseline_value is not None: + threshold = _get_threshold_for_metric(baseline_data_list, metric) + threshold_line_value = baseline_value * (1 - threshold) + + charts.append( + _generate_svg_chart( + hist_pts, + metric, + label, + new_points=new_pts, + baseline_value=baseline_value, + threshold_line_value=threshold_line_value, + ) + ) + + header = escape_html(f"{test_case} [{gpu_type}]") + section = f""" +
+ {header} +
+ {"".join(charts)} +
+
+ """ + sections_html.append(section) + + total_new = len(new_data_list) + html = f""" + + + + Perf Sanity Pre-Merge Results + + + +

Perf Sanity Pre-Merge Results

+

{len(new_groups)} test case(s) · {total_new} new data point(s)

+ {"".join(sections_html)} + + +""" + with open(output_file, "w", encoding="utf-8") as f: + f.write(html) + + print(f"Generated pre-merge perf report with {len(new_groups)} test cases: {output_file}") + + +# --------------------------------------------------------------------------- +# CLI +# --------------------------------------------------------------------------- + + +def main(): + parser = argparse.ArgumentParser( + description="Generate a pre-merge HTML report with historical " + "performance charts, baseline, and threshold lines." + ) + parser.add_argument( + "--input-files", + type=str, + required=True, + help="Comma-separated list of perf_data.yaml paths", + ) + parser.add_argument("--output-file", type=str, required=True, help="Output HTML file path") + args = parser.parse_args() + + new_data_list = load_perf_data(args.input_files) + history_grouped = get_pre_merge_history_data(new_data_list) + generate_pre_merge_html(new_data_list, history_grouped, args.output_file) + + +if __name__ == "__main__": + main() diff --git a/jenkins/scripts/perf/local/README.md b/jenkins/scripts/perf/local/README.md new file mode 100644 index 000000000000..d11e9d7b2297 --- /dev/null +++ b/jenkins/scripts/perf/local/README.md @@ -0,0 +1,101 @@ +# Local SLURM Launch Scripts + +## Overview + +This directory contains scripts for running perf sanity tests locally via SLURM. The workflow has three steps: + +1. **`submit.py`** generates a complete `slurm_launch.sh` script. It reads the test config YAML, detects aggregated vs disaggregated mode, and combines SBATCH parameters + environment variables + the appropriate draft template (`jenkins/scripts/perf/aggregated/slurm_launch_draft.sh` or `jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh`) into a single launch script. A `test_list.txt` is also written to the work directory. + +2. **`sbatch slurm_launch.sh`** submits the job to SLURM. Inside the launch script: + - For **aggregated** mode, a single `srun` invokes `slurm_run.sh`. + - For **disaggregated** mode, `srun` first runs `slurm_install.sh` on all nodes, then launches separate `srun` commands for gen workers, ctx workers, the disagg server, and the benchmark client. + +3. **`slurm_install.sh`** handles build and installation inside the container. It optionally builds the TensorRT-LLM wheel (when `--build-wheel` is set) and then runs `pip install -e .` plus dev requirements. A lock-file mechanism ensures only one process per node performs the install while others wait. + +4. **`slurm_run.sh`** runs the pytest command. In aggregated mode, it first sources `slurm_install.sh` to run the install step, then executes the pytest command. In disaggregated mode, the install has already been done by the launch script, so `slurm_run.sh` runs pytest directly. + +``` +submit.py + | + v +slurm_launch.sh (generated) + | + |-- srun --> slurm_install.sh (build wheel + pip install) + |-- srun --> slurm_run.sh (run pytest) +``` + +## Optional Arguments + +- `--test-list`: Test string, e.g., `perf/test_perf_sanity.py::test_e2e[aggr-config-test_name]`. If both `--test-list` and `--config-file` are provided, `--test-list` takes precedence. +- `--config-file`: Path to config YAML file. +- `--test-name`: Test name (only used for aggregated mode when `--config-file` is provided). +- `--time`: SLURM time limit (default: `02:00:00`). +- `--mounts`: Container mounts. +- `--work-dir`: Work directory (used for both workdir and container-workdir). +- `--draft-launch-sh`: Path to draft-launch.sh script. +- `--launch-sh`: Path to output launch.sh script. +- `--run-sh`: Path to slurm_run.sh script. +- `--install-sh`: Path to slurm_install.sh script. +- `--llm-src`: Path to LLM source code. +- `--build-wheel`: Add this flag to build the wheel before running tests. +- `--install-mode`: Installation mode - `source` (pip install -e ., default) or `wheel` (pip install *.whl). +- `--capture-nsys`: Add this flag to capture an nsys profile during the test run. +- `--nsys-start-stop`: Nsys start-stop range (default: `1-100`). +- `--ctx-nsys-start-stop`: CTX Worker Nsys start-stop range (default: `1-100`). +- `--gen-nsys-start-stop`: GEN Worker Nsys start-stop range (default: `1-100`). + +`--image` can be obtained by: + +```bash +# B200 +image=$(grep LLM_DOCKER_IMAGE $trtllm/jenkins/current_image_tags.properties | head -1 | awk -F "=" '{print $2}' ) +image=$(echo $image | sed 's|urm.nvidia.com/|urm.nvidia.com#|g') +# GB200 +image=$(grep LLM_SBSA_DOCKER_IMAGE $trtllm/jenkins/current_image_tags.properties | head -1 | awk -F "=" '{print $2}' ) +image=$(echo $image | sed 's|urm.nvidia.com/|urm.nvidia.com#|g') +``` + +## Cluster Settings + +| Cluster | `--partition` | `--account` | +|---------|---------------|-------------| +| OCI | `batch` | `coreai_comparch_trtllm` | +| DLCluster | `gb200nvl72_preprod` | `coreai_comparch_trtllm` | + +## Examples + +### Aggregated Mode + +```bash +python3 submit.py --test-list "perf/test_perf_sanity.py::test_e2e[aggr-deepseek_r1_fp4_v2_2_nodes_grace_blackwell-r1_fp4_v2_tep8_mtp3]" \ + --draft-launch-sh $trtllm/jenkins/scripts/perf/aggregated/slurm_launch_draft.sh \ + --launch-sh $work_dir/slurm_launch.sh \ + --install-sh $trtllm/jenkins/scripts/perf/local/slurm_install.sh \ + --run-sh $trtllm/jenkins/scripts/perf/local/slurm_run.sh \ + --llm-src $trtllm \ + --work-dir $work_dir \ + --partition $partition \ + --account $account \ + --job-name aggr_test \ + --image $image \ + --mounts $mounts \ + --llm-models-root $llm_models_path +``` + +### Disaggregated Mode + +```bash +python3 submit.py --test-list "perf/test_perf_sanity.py::test_e2e[disagg-e2e-gb200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX]" \ + --draft-launch-sh $trtllm/jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh \ + --launch-sh $work_dir/slurm_launch.sh \ + --install-sh $trtllm/jenkins/scripts/perf/local/slurm_install.sh \ + --run-sh $trtllm/jenkins/scripts/perf/local/slurm_run.sh \ + --llm-src $trtllm \ + --work-dir $work_dir \ + --partition $partition \ + --account $account \ + --job-name disagg_test \ + --image $image \ + --mounts $mounts \ + --llm-models-root $llm_models_path +``` diff --git a/jenkins/scripts/perf/local/run_agg_local.sh b/jenkins/scripts/perf/local/run_agg_local.sh new file mode 100755 index 000000000000..819f535ebf0d --- /dev/null +++ b/jenkins/scripts/perf/local/run_agg_local.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Run all aggregated perf sanity tests on OCI. +# No wheel build, no nsys capture. + +set -euo pipefail + +REPO_ROOT="/lustre/fs1/portfolios/coreai/projects/coreai_comparch_trtllm/users/chenfeiz/repo/trtllm-2" +LOCAL_DIR="${REPO_ROOT}/jenkins/scripts/perf/local" +IMAGE="urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm:pytorch-25.12-py3-aarch64-ubuntu24.04-trt10.14.1.48-skip-tritondevel-202602011118-10901" +MOUNTS="/home/chenfeiz/:/home/chenfeiz/,/home/chenfeiz/.cache:/root/.cache,/lustre/fsw/portfolios/coreai/:/lustre/fsw/portfolios/coreai/,/lustre/fs1/portfolios/coreai/:/lustre/fs1/portfolios/coreai/" +LLM_MODELS_ROOT="/lustre/fs1/portfolios/coreai/projects/coreai_tensorrt_ci/llm-models" +PARTITION="batch" +ACCOUNT="coreai_comparch_trtllm" +JOB_NAME="perf_test" + +TESTS=( + "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_v32_fp4_grace_blackwell-v32_fp4_tep4_mtp3_1k1k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_v32_fp4_grace_blackwell-v32_fp4_tep4_mtp3_8k1k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-k2_thinking_fp4_2_nodes_grace_blackwell-k2_thinking_fp4_dep8_32k8k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-k2_thinking_fp4_2_nodes_grace_blackwell-k2_thinking_fp4_tep8_32k8k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-k2_thinking_fp4_grace_blackwell-k2_thinking_fp4_tep4_8k1k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell-r1_fp4_v2_dep4_mtp1_1k8k]" + # "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_v32_fp4_blackwell-v32_fp4_dep8_mtp1_8k1k]" + # "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_blackwell-r1_fp4_v2_dep8_mtp1_8k1k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell-r1_fp4_v2_tp4_mtp3_1k8k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell-r1_fp4_v2_tep4_mtp3_8k1k]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_2_nodes_grace_blackwell-r1_fp4_v2_tep8_mtp3]" + "perf/test_perf_sanity.py::test_e2e[aggr_upload-ctx_only-gb200_kimi-k2-thinking-fp4_8k1k_con4_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX]" + # "perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_v32_fp4_blackwell-v32_fp4_tep8_mtp3_8k1k]" +) + +for TEST in "${TESTS[@]}"; do + # Extract the config name between "aggr_upload-" and the closing "]" + CONFIG_NAME=$(echo "$TEST" | sed 's/.*aggr_upload-\(.*\)]/\1/') + + cd "${LOCAL_DIR}" + python3 submit.py --test-list "$TEST" \ + --partition "$PARTITION" \ + --account "$ACCOUNT" \ + --job-name "$JOB_NAME" \ + --image "$IMAGE" \ + --mounts "$MOUNTS" \ + --llm-models-root "$LLM_MODELS_ROOT" \ + --work-dir "${LOCAL_DIR}/agg-${CONFIG_NAME}" + + cd "${LOCAL_DIR}/agg-${CONFIG_NAME}" && sbatch slurm_launch.sh +done diff --git a/jenkins/scripts/perf/local/run_e2e_local.sh b/jenkins/scripts/perf/local/run_e2e_local.sh new file mode 100755 index 000000000000..942e2abdeed1 --- /dev/null +++ b/jenkins/scripts/perf/local/run_e2e_local.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Run all GB200 disagg e2e perf sanity tests on OCI. +# No wheel build, no nsys capture. + +set -euo pipefail + +REPO_ROOT="/lustre/fs1/portfolios/coreai/projects/coreai_comparch_trtllm/users/chenfeiz/repo/trtllm-2" +LOCAL_DIR="${REPO_ROOT}/jenkins/scripts/perf/local" +IMAGE="urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm:pytorch-25.12-py3-aarch64-ubuntu24.04-trt10.14.1.48-skip-tritondevel-202602011118-10901" +MOUNTS="/home/chenfeiz/:/home/chenfeiz/,/home/chenfeiz/.cache:/root/.cache,/lustre/fsw/portfolios/coreai/:/lustre/fsw/portfolios/coreai/,/lustre/fs1/portfolios/coreai/:/lustre/fs1/portfolios/coreai/" +LLM_MODELS_ROOT="/lustre/fs1/portfolios/coreai/projects/coreai_tensorrt_ci/llm-models" +PARTITION="batch" +ACCOUNT="coreai_comparch_trtllm" +JOB_NAME="perf_test" + +TESTS=( + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_gpt-oss-120b-fp4_1k1k_con2048_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_gpt-oss-120b-fp4_1k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_gpt-oss-120b-fp4_8k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_gpt-oss-120b-fp4_1k1k_con64_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_gpt-oss-120b-fp4_8k1k_con128_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_gpt-oss-120b-fp4_8k1k_con4_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_qwen3-235b-fp4_8k1k_con64_ctx1_tp1_gen1_tep4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_deepseek-r1-fp4_1k1k_con3072_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_deepseek-v32-fp4_1k1k_con2048_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_kimi-k2-thinking-fp4_1k1k_con4_ctx1_dep4_gen1_tep4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_qwen3-235b-fp4_8k1k_con1024_ctx1_tp1_gen1_dep8_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-gb200_deepseek-r1-fp4_128k8k_con1_ctx1_pp8_gen1_tep8_eplb0_mtp3_ccb-UCX]" +) + +for TEST in "${TESTS[@]}"; do + # Extract the config name between "e2e-" and the closing "]" + CONFIG_NAME=$(echo "$TEST" | sed 's/.*e2e-\(.*\)]/\1/') + + cd "${LOCAL_DIR}" + python3 submit.py --test-list "$TEST" \ + --partition "$PARTITION" \ + --account "$ACCOUNT" \ + --job-name "$JOB_NAME" \ + --image "$IMAGE" \ + --mounts "$MOUNTS" \ + --llm-models-root "$LLM_MODELS_ROOT" \ + --work-dir "${LOCAL_DIR}/e2e-${CONFIG_NAME}" + + cd "${LOCAL_DIR}/e2e-${CONFIG_NAME}" && sbatch slurm_launch.sh +done diff --git a/jenkins/scripts/perf/local/run_gen_only_local.sh b/jenkins/scripts/perf/local/run_gen_only_local.sh new file mode 100755 index 000000000000..af9b05d3967a --- /dev/null +++ b/jenkins/scripts/perf/local/run_gen_only_local.sh @@ -0,0 +1,49 @@ +#!/bin/bash +# Run all GB200 disagg gen_only perf sanity tests on OCI. +# No wheel build, no nsys capture. + +set -euo pipefail + +REPO_ROOT="/lustre/fs1/portfolios/coreai/projects/coreai_comparch_trtllm/users/chenfeiz/repo/trtllm-2" +LOCAL_DIR="${REPO_ROOT}/jenkins/scripts/perf/local" +IMAGE="urm.nvidia.com/sw-tensorrt-docker/tensorrt-llm:pytorch-25.12-py3-aarch64-ubuntu24.04-trt10.14.1.48-skip-tritondevel-202602011118-10901" +MOUNTS="/home/chenfeiz/:/home/chenfeiz/,/home/chenfeiz/.cache:/root/.cache,/lustre/fsw/portfolios/coreai/:/lustre/fsw/portfolios/coreai/,/lustre/fs1/portfolios/coreai/:/lustre/fs1/portfolios/coreai/" +LLM_MODELS_ROOT="/lustre/fs1/portfolios/coreai/projects/coreai_tensorrt_ci/llm-models" +PARTITION="batch" +ACCOUNT="coreai_comparch_trtllm" +JOB_NAME="perf_test" + +TESTS=( + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_gpt-oss-120b-fp4_1k1k_con2048_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_gpt-oss-120b-fp4_1k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_gpt-oss-120b-fp4_8k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_gpt-oss-120b-fp4_1k1k_con64_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_gpt-oss-120b-fp4_8k1k_con128_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_gpt-oss-120b-fp4_8k1k_con4_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_qwen3-235b-fp4_8k1k_con64_ctx1_tp1_gen1_tep4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_deepseek-r1-fp4_1k1k_con3072_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_deepseek-v32-fp4_1k1k_con2048_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_kimi-k2-thinking-fp4_1k1k_con4_ctx1_dep4_gen1_tep4_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_qwen3-235b-fp4_8k1k_con1024_ctx1_tp1_gen1_dep8_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX]" + "perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb200_deepseek-r1-fp4_128k8k_con1_ctx1_pp8_gen1_tep8_eplb0_mtp3_ccb-UCX]" +) + +for TEST in "${TESTS[@]}"; do + # Extract the config name between "gen_only-" and the closing "]" + CONFIG_NAME=$(echo "$TEST" | sed 's/.*gen_only-\(.*\)]/\1/') + + cd "${LOCAL_DIR}" + python3 submit.py --test-list "$TEST" \ + --partition "$PARTITION" \ + --account "$ACCOUNT" \ + --job-name "$JOB_NAME" \ + --image "$IMAGE" \ + --mounts "$MOUNTS" \ + --llm-models-root "$LLM_MODELS_ROOT" \ + --work-dir "${LOCAL_DIR}/gen_only-1-${CONFIG_NAME}" + + cd "${LOCAL_DIR}/gen_only-1-${CONFIG_NAME}" && sbatch slurm_launch.sh +done diff --git a/jenkins/scripts/perf/local/slurm_install.sh b/jenkins/scripts/perf/local/slurm_install.sh new file mode 100755 index 000000000000..026867bbed2d --- /dev/null +++ b/jenkins/scripts/perf/local/slurm_install.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# Set up error handling +set -xEeuo pipefail +trap 'rc=$?; echo "Error in file ${BASH_SOURCE[0]} on line $LINENO: $BASH_COMMAND (exit $rc)"; exit $rc' ERR + +# Source bash utilities for retry_command +source "$(dirname "${BASH_SOURCE[0]}")/../../bash_utils.sh" + +slurm_build_wheel() { + if [ "${BUILD_WHEEL:-false}" != "true" ]; then + echo "BUILD_WHEEL is not true, skipping wheel build" + return + fi + + build_lock_file="build_wheel_lock_${SLURM_JOB_ID:-local}.lock" + if [ "${SLURM_NODEID:-0}" -eq 0 ] && [ "${SLURM_LOCALID:-0}" -eq 0 ]; then + cd $jobWorkspace + if [ -f "$build_lock_file" ]; then + rm -f "$build_lock_file" + fi + + echo "Building wheel on node ${SLURM_NODEID:-0}, task ${SLURM_LOCALID:-0}" + retry_command bash -c "cd $llmSrcNode && rm -rf .venv-3.12 && python3 ./scripts/build_wheel.py --trt_root /usr/local/tensorrt --benchmarks --use_ccache --cuda_architectures '100-real' --clean -c" + + cd $jobWorkspace + echo "(Writing build wheel lock) Lock file: $build_lock_file" + touch "$build_lock_file" + else + cd $jobWorkspace + echo "(Waiting for build wheel lock) Lock file: $build_lock_file" + while [ ! -f "$build_lock_file" ]; do + sleep 10 + done + fi + echo "Build wheel completed" +} + +slurm_install_setup() { + lock_file="install_lock_job_${SLURM_JOB_ID:-local}_node_${SLURM_NODEID:-0}.lock" + if [ "${SLURM_LOCALID:-0}" -eq 0 ]; then + cd /tmp + if [ -f "$lock_file" ]; then + rm -f "$lock_file" + fi + + echo "(Installing TensorRT-LLM and requirements) Install mode: ${INSTALL_MODE:-source}" + + # Support two installation modes: source (default) and wheel + if [ "${INSTALL_MODE:-source}" = "wheel" ]; then + # Wheel installation mode + echo "Installing from wheel..." + WHEEL_FILE=$(find "$llmSrcNode/build" -name "tensorrt_llm-*.whl" -type f 2>/dev/null | head -1) + + if [ -n "$WHEEL_FILE" ]; then + echo "Found wheel: $WHEEL_FILE" + retry_command pip install --retries 10 "$WHEEL_FILE" + retry_command pip install --retries 10 -r "$llmSrcNode/requirements-dev.txt" + else + echo "ERROR: No wheel file found in $llmSrcNode/build, falling back to source install" + retry_command bash -c "cd $llmSrcNode && pip install --retries 10 -e . && pip install --retries 10 -r requirements-dev.txt" + fi + else + # Source installation mode (default) + retry_command bash -c "cd $llmSrcNode && pip install --retries 10 -e . && pip install --retries 10 -r requirements-dev.txt" + fi + + cd /tmp + echo "(Writing install lock) Current directory: $(pwd)" + touch "$lock_file" + else + cd /tmp + echo "(Waiting for install lock) Current directory: $(pwd)" + while [ ! -f "$lock_file" ]; do + sleep 10 + done + fi + echo "Install completed" +} + +# Only run when script is executed directly (not sourced) +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + slurm_build_wheel + slurm_install_setup +fi diff --git a/jenkins/scripts/perf/local/slurm_run.sh b/jenkins/scripts/perf/local/slurm_run.sh new file mode 100755 index 000000000000..b517638f762f --- /dev/null +++ b/jenkins/scripts/perf/local/slurm_run.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Set up error handling +set -xEeuo pipefail +trap 'rc=$?; echo "Error in file ${BASH_SOURCE[0]} on line $LINENO: $BASH_COMMAND (exit $rc)"; exit $rc' ERR + +# Aggregated mode will run install together with pytest in slurm_run.sh +# Disaggregated mode will run install separately in slurm_install.sh +if [[ -z "${DISAGG_SERVING_TYPE:-}" ]]; then + installScriptPath="$(dirname "${BASH_SOURCE[0]}")/slurm_install.sh" + source "$installScriptPath" + slurm_build_wheel + slurm_install_setup +fi + +cd $llmSrcNode/tests/integration/defs + +# Turn off "exit on error" so the following lines always run +set +e + +pytest_exit_code=0 + +eval $pytestCommand +pytest_exit_code=$? +echo "Rank${SLURM_PROCID} Pytest finished execution with exit code $pytest_exit_code" + +exit $pytest_exit_code diff --git a/jenkins/scripts/perf/local/submit.py b/jenkins/scripts/perf/local/submit.py new file mode 100755 index 000000000000..e0f7abcd0f5a --- /dev/null +++ b/jenkins/scripts/perf/local/submit.py @@ -0,0 +1,724 @@ +#!/usr/bin/env python3 +import argparse +import os +import re +from datetime import datetime + +import yaml + +AGG_CONFIG_FOLDER = os.environ.get("AGG_CONFIG_FOLDER", "tests/scripts/perf-sanity/aggregated") +DISAGG_CONFIG_FOLDER = os.environ.get( + "DISAGG_CONFIG_FOLDER", "tests/scripts/perf-sanity/disaggregated" +) + + +def get_llm_src_default(): + """Get default llm_src path by going up 4 directories from this script.""" + script_dir = os.path.dirname(os.path.abspath(__file__)) + return os.path.normpath(os.path.join(script_dir, "..", "..", "..", "..")) + + +def detect_config_type(config): + """Detect if config is disagg (has worker_config) or aggr (has server_configs).""" + if "worker_config" in config: + return "disagg" + elif "server_configs" in config: + return "aggr" + else: + raise ValueError("Cannot detect config type: missing worker_config or server_configs") + + +def extract_test_case_name(test_string): + """Extract test case name from test string with brackets. + + Args: + test_string: Full test string like 'perf/test_perf_sanity.py::test_e2e[aggr-config-test]' + + Returns: + str: Test case name (content inside brackets), e.g., 'aggr-config-test' + """ + # Remove TIMEOUT suffix if present + test_string = re.sub(r"\s+TIMEOUT\s*\(\d+\)\s*$", "", test_string.strip()) + + if "[" not in test_string or "]" not in test_string: + raise ValueError( + f"Invalid test string format. Expected test name with brackets: {test_string}" + ) + return test_string.split("[")[-1].split("]")[0] + + +def parse_test_string(test_case_name: str): + """Parse test case name to get config base name, select pattern, runtime, and benchmark_mode. + + Test name formats: + - Disagg e2e: disagg_upload-e2e-{config_base} + - Disagg gen_only: disagg_upload-gen_only-{config_base} + - ctx_only: aggr_upload-ctx_only-{config_base} (runs aggr mode but reads disagg config) + - Regular aggr: aggr_upload-{config}-{server_name} + + Returns: + tuple: (config_base_name, select_pattern, runtime_mode, benchmark_mode) + - runtime_mode: "aggregated" or "disaggregated" + - benchmark_mode: "e2e", "gen_only", "ctx_only", or None (for normal aggr) + """ + labels = test_case_name.split("-") + + assert len(labels) > 1, "perf_sanity test must have a config file!" + + prefix = labels[0] + is_disagg_prefix = "disagg" in prefix + is_aggr_prefix = "aggr" in prefix + + if is_disagg_prefix: + # Disagg format: disagg_upload-{e2e|gen_only}-{config_base} + assert len(labels) > 2, "Disagg test must have benchmark_mode and config!" + benchmark_mode = labels[1] # e2e or gen_only + assert benchmark_mode in ("e2e", "gen_only"), ( + f"Invalid benchmark_mode for disagg: {benchmark_mode}" + ) + runtime_mode = "disaggregated" + config_base_name = "-".join(labels[2:]) + select_pattern = None + elif is_aggr_prefix: + # Check if this is ctx_only (aggr_upload-ctx_only-{config_base}) + if len(labels) > 2 and labels[1] == "ctx_only": + # ctx_only: aggr_upload-ctx_only-{config_base} + # Runs in aggregated mode but reads disagg config + benchmark_mode = "ctx_only" + runtime_mode = "aggregated" + config_base_name = "-".join(labels[2:]) + select_pattern = None + else: + # Regular aggr: aggr_upload-config_yml or aggr_upload-config_yml-server_config_name + benchmark_mode = None + runtime_mode = "aggregated" + config_base_name = labels[1] + # select_pattern is server config name (e.g., "r1_fp8_dep8_mtp1_1k1k") + select_pattern = "-".join(labels[2:]) if len(labels) > 2 else None + else: + raise ValueError(f"Invalid test name prefix: {prefix}") + + return config_base_name, select_pattern, runtime_mode, benchmark_mode + + +def get_config_yaml_path(llm_src, config_base_name, benchmark_mode): + """Get config yaml path based on benchmark_mode. + + Args: + llm_src: Path to LLM source code + config_base_name: Base name of config file (without .yaml extension) + benchmark_mode: "e2e", "gen_only", "ctx_only", or None (for normal aggr) + + Returns: + str: Full path to config yaml file + """ + if benchmark_mode in ("e2e", "gen_only", "ctx_only"): + config_dir = DISAGG_CONFIG_FOLDER + else: + config_dir = AGG_CONFIG_FOLDER + # If relative path, join with llm root + if not os.path.isabs(config_dir): + config_dir = os.path.join(llm_src, config_dir) + + config_yaml_path = os.path.join(config_dir, f"{config_base_name}.yaml") + + if not os.path.exists(config_yaml_path): + raise FileNotFoundError(f"Config file not found: {config_yaml_path}") + + return config_yaml_path + + +def get_hardware_config(config, runtime_mode, benchmark_mode, test_name=None): + """Get hardware config based on mode.""" + hardware = config.get("hardware", {}) + gpus_per_node = hardware.get("gpus_per_node") + + if gpus_per_node is None: + raise ValueError("Missing gpus_per_node in hardware configuration") + + # ctx_only mode reads disagg config but runs in aggregated mode + if benchmark_mode == "ctx_only": + # Use ctx worker config to determine hardware + worker_config = config.get("worker_config", {}) + ctx_config = worker_config.get("ctx", {}) + ctx_tp = ctx_config.get("tensor_parallel_size", 1) + ctx_pp = ctx_config.get("pipeline_parallel_size", 1) + ctx_cp = ctx_config.get("context_parallel_size", 1) + gpus_per_server = ctx_tp * ctx_pp * ctx_cp + + nodes_per_server = (gpus_per_server + gpus_per_node - 1) // gpus_per_node + total_nodes = nodes_per_server + total_gpus = total_nodes * gpus_per_node + gpus_per_node_per_server = min(gpus_per_server, gpus_per_node) + + return { + "gpus_per_node": gpus_per_node, + "gpus_per_server": gpus_per_server, + "nodes_per_server": nodes_per_server, + "gpus_per_node_per_server": gpus_per_node_per_server, + "total_nodes": total_nodes, + "total_gpus": total_gpus, + } + elif runtime_mode == "aggregated": + # Normal aggregated mode + server_configs = config.get("server_configs", []) + server_config = None + for sc in server_configs: + if sc.get("name") == test_name: + server_config = sc + break + + if server_config is None: + raise ValueError(f"Server config not found for test_name: {test_name}") + + tp = server_config.get("tensor_parallel_size", 1) + pp = server_config.get("pipeline_parallel_size", 1) + cp = server_config.get("context_parallel_size", 1) + gpus_per_server = tp * pp * cp + + nodes_per_server = (gpus_per_server + gpus_per_node - 1) // gpus_per_node + total_nodes = nodes_per_server + total_gpus = total_nodes * gpus_per_node + gpus_per_node_per_server = min(gpus_per_server, gpus_per_node) + + return { + "gpus_per_node": gpus_per_node, + "gpus_per_server": gpus_per_server, + "nodes_per_server": nodes_per_server, + "gpus_per_node_per_server": gpus_per_node_per_server, + "total_nodes": total_nodes, + "total_gpus": total_gpus, + } + else: + # Disaggregated mode (e2e or gen_only) + worker_config = config.get("worker_config", {}) + + num_ctx_servers = ( + 0 + if benchmark_mode == "gen_only" + and "gen_only_no_context" in config.get("benchmark", {}).get("mode", "") + else hardware.get("num_ctx_servers") + ) + num_gen_servers = hardware.get("num_gen_servers") + + ctx_config = worker_config.get("ctx", {}) + gen_config = worker_config.get("gen", {}) + ctx_tp = ctx_config.get("tensor_parallel_size", 1) + ctx_pp = ctx_config.get("pipeline_parallel_size", 1) + ctx_cp = ctx_config.get("context_parallel_size", 1) + gpus_per_ctx_server = ctx_tp * ctx_pp * ctx_cp + gen_tp = gen_config.get("tensor_parallel_size", 1) + gen_pp = gen_config.get("pipeline_parallel_size", 1) + gen_cp = gen_config.get("context_parallel_size", 1) + gpus_per_gen_server = gen_tp * gen_pp * gen_cp + + if None in [ + num_ctx_servers, + num_gen_servers, + gpus_per_ctx_server, + gpus_per_gen_server, + ]: + raise ValueError("Missing required hardware configuration") + + nodes_per_ctx_server = (gpus_per_ctx_server + gpus_per_node - 1) // gpus_per_node + nodes_per_gen_server = (gpus_per_gen_server + gpus_per_node - 1) // gpus_per_node + + gpus_per_node_per_ctx_server = min(gpus_per_ctx_server, gpus_per_node) + gpus_per_node_per_gen_server = min(gpus_per_gen_server, gpus_per_node) + + total_nodes = ( + num_ctx_servers * nodes_per_ctx_server + num_gen_servers * nodes_per_gen_server + ) + total_gpus = total_nodes * gpus_per_node + + return { + "num_ctx_servers": num_ctx_servers, + "num_gen_servers": num_gen_servers, + "gpus_per_node": gpus_per_node, + "gpus_per_ctx_server": gpus_per_ctx_server, + "gpus_per_gen_server": gpus_per_gen_server, + "nodes_per_ctx_server": nodes_per_ctx_server, + "nodes_per_gen_server": nodes_per_gen_server, + "gpus_per_node_per_ctx_server": gpus_per_node_per_ctx_server, + "gpus_per_node_per_gen_server": gpus_per_node_per_gen_server, + "total_nodes": total_nodes, + "total_gpus": total_gpus, + } + + +def get_env_config(config, runtime_mode): + """Get env config based on mode.""" + if runtime_mode == "aggregated": + return {} + env = config.get("environment", {}) + return { + "worker_env_var": env.get("worker_env_var", ""), + "server_env_var": env.get("server_env_var", ""), + "benchmark_env_var": env.get("benchmark_env_var", ""), + } + + +def get_benchmark_config(config, benchmark_mode): + """Get benchmark config based on mode.""" + if benchmark_mode is None: + return {} + benchmark = config.get("benchmark", {}) + concurrency_str = benchmark.get("concurrency_list", "1") + concurrency = int(concurrency_str) if isinstance(concurrency_str, str) else concurrency_str + + return { + "mode": benchmark_mode, + "concurrency": concurrency, + } + + +def generate_sbatch_params(args, hardware_config, work_dir): + """Generate #SBATCH parameters.""" + total_nodes = hardware_config["total_nodes"] + gpus_per_node = hardware_config["gpus_per_node"] + total_gpus = hardware_config["total_gpus"] + lines = [ + "#!/bin/bash", + f"#SBATCH --nodes={total_nodes}", + f"#SBATCH --segment={total_nodes}", + f"#SBATCH --ntasks={total_gpus}", + f"#SBATCH --ntasks-per-node={gpus_per_node}", + f"#SBATCH --gpus-per-node={gpus_per_node}", + f"#SBATCH --gres=gpu:{gpus_per_node}", + f"#SBATCH --partition={args.partition}", + f"#SBATCH --time={args.time}", + f"#SBATCH --account={args.account}", + f"#SBATCH -J {args.job_name}", + f"#SBATCH -o {work_dir}/slurm-%j.out", + ] + return lines + + +def generate_srun_args(args, runtime_mode, timestamp): + """Generate srun arguments.""" + is_aggr = runtime_mode == "aggregated" + container_name = f"{'aggr' if is_aggr else 'disagg'}_test-{timestamp}" + + lines = [ + f"--container-name={container_name}", + f"--container-image={args.image}", + ] + + if args.work_dir: + lines.append(f"--container-workdir={args.work_dir}") + + if args.mounts: + lines.append(f"--container-mounts={args.mounts}") + + lines.append("--container-env=NVIDIA_IMEX_CHANNELS") + + if is_aggr: + lines.append("--mpi=pmi2") + + return lines + + +def generate_pytest_command( + llm_src, work_dir, config_file_base_name, select_pattern, runtime_mode, benchmark_mode +): + """Generate pytest command and test list.""" + # Generate test list content based on runtime_mode and benchmark_mode + if runtime_mode == "disaggregated": + # disagg_upload-{e2e|gen_only}-{config_base} + test_list_content = ( + f"perf/test_perf_sanity.py::test_e2e[disagg-{benchmark_mode}-{config_file_base_name}]" + ) + elif benchmark_mode == "ctx_only": + # aggr_upload-ctx_only-{config_base} + test_list_content = ( + f"perf/test_perf_sanity.py::test_e2e[aggr-ctx_only-{config_file_base_name}]" + ) + else: + # Normal aggr: aggr-{config}-{select_pattern} + test_list_content = ( + f"perf/test_perf_sanity.py::test_e2e[aggr-{config_file_base_name}-{select_pattern}]" + ) + + test_list_path = os.path.join(work_dir, "test_list.txt") + + pytest_command = ( + f"pytest -v -s " + f"--test-prefix={llm_src}/tests/integration/defs " + f"--test-list={test_list_path} " + f"--output-dir={work_dir} " + f"-o junit_logging=out-err" + ) + + return pytest_command, test_list_content, test_list_path + + +def remove_whitespace_lines(lines): + """Remove empty lines and strip whitespace.""" + return [line for line in lines if line.strip()] + + +def main(): + parser = argparse.ArgumentParser( + description="Generate SLURM launch script for local runs (aggregated or disaggregated)" + ) + parser.add_argument( + "--test-list", + default="", + help="Test string, e.g., 'perf/test_perf_sanity.py::test_e2e[aggr-config-test_name]'. " + "If both --test-list and --config-file are provided, --test-list takes precedence.", + ) + parser.add_argument("--config-file", default="", help="Path to config YAML file") + parser.add_argument( + "--test-name", + default="", + help="Test name (only used for normal aggregated mode when --config-file is provided)", + ) + parser.add_argument( + "--benchmark-mode", + default="", + choices=["", "e2e", "gen_only", "ctx_only"], + help="Benchmark mode for disagg config (when --config-file is provided)", + ) + parser.add_argument("--partition", required=True, help="SLURM partition") + parser.add_argument("--time", default="02:00:00", help="SLURM time limit") + parser.add_argument("--account", required=True, help="SLURM account") + parser.add_argument("--job-name", required=True, help="SLURM job name") + parser.add_argument("--image", required=True, help="Container image") + parser.add_argument("--mounts", default="", help="Container mounts") + parser.add_argument( + "--work-dir", + default="", + help="Work directory (used for both workdir and container-workdir)", + ) + parser.add_argument("--draft-launch-sh", default="", help="Path to draft-launch.sh script") + parser.add_argument("--launch-sh", default="", help="Path to output launch.sh script") + parser.add_argument("--run-sh", default="", help="Path to slurm_run.sh script") + parser.add_argument("--install-sh", default="", help="Path to slurm_install.sh script") + parser.add_argument("--llm-src", default="", help="Path to LLM source code") + parser.add_argument("--llm-models-root", required=True, help="Path to LLM models root") + parser.add_argument( + "--build-wheel", action="store_true", help="Build wheel before running tests" + ) + parser.add_argument( + "--install-mode", + default="source", + choices=["source", "wheel"], + help="Installation mode: source (pip install -e ., default) or wheel (pip install *.whl)", + ) + parser.add_argument("--capture-nsys", action="store_true", help="Capture nsys profile") + parser.add_argument( + "--nsys-start-stop", + default="1-100", + help="Nsys start-stop range for aggregated mode (default: 1-100)", + ) + parser.add_argument( + "--ctx-nsys-start-stop", + default="1-100", + help="Nsys start-stop range for context workers in disaggregated mode (default: 1-100)", + ) + parser.add_argument( + "--gen-nsys-start-stop", + default="1-100", + help="Nsys start-stop range for generation workers in disaggregated mode (default: 1-100)", + ) + + args = parser.parse_args() + + # Determine llm_src + llm_src = args.llm_src if args.llm_src else get_llm_src_default() + llm_src = os.path.abspath(llm_src) + + # Determine config_yaml, config_file_base_name, select_pattern, runtime_mode, and benchmark_mode + # --test-list takes precedence over --config-file + if args.test_list: + test_case_name = extract_test_case_name(args.test_list) + config_file_base_name, select_pattern, runtime_mode, benchmark_mode = parse_test_string( + test_case_name + ) + config_yaml = get_config_yaml_path(llm_src, config_file_base_name, benchmark_mode) + elif args.config_file: + config_yaml = args.config_file + config_file_base_name = os.path.splitext(os.path.basename(config_yaml))[0] + + # Load config to detect type + with open(config_yaml, "r") as f: + config = yaml.safe_load(f) + + config_type = detect_config_type(config) + + if config_type == "disagg": + # Disagg config - need benchmark_mode + benchmark_mode = args.benchmark_mode if args.benchmark_mode else "e2e" + if benchmark_mode == "ctx_only": + runtime_mode = "aggregated" + else: + runtime_mode = "disaggregated" + select_pattern = None + else: + # Aggr config + runtime_mode = "aggregated" + benchmark_mode = None + select_pattern = args.test_name + if not select_pattern: + raise ValueError("--test-name is required for aggregated config") + else: + raise ValueError("Either --test-list or --config-file must be provided") + + # Load config if not already loaded + if not args.config_file: + with open(config_yaml, "r") as f: + config = yaml.safe_load(f) + + # Create timestamp + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + + # Determine work_dir + work_dir = args.work_dir + if not work_dir: + work_dir = os.path.join(llm_src, "jenkins", "scripts", "perf", "local", timestamp) + os.makedirs(work_dir, exist_ok=True) + + # Determine paths + launch_sh = args.launch_sh if args.launch_sh else os.path.join(work_dir, "slurm_launch.sh") + run_sh = ( + args.run_sh + if args.run_sh + else os.path.join(llm_src, "jenkins", "scripts", "perf", "local", "slurm_run.sh") + ) + install_sh = ( + args.install_sh + if args.install_sh + else os.path.join(llm_src, "jenkins", "scripts", "perf", "local", "slurm_install.sh") + ) + draft_launch_sh = args.draft_launch_sh + if not draft_launch_sh: + draft_launch_sh = os.path.join( + llm_src, + "jenkins", + "scripts", + "perf", + "disaggregated" if runtime_mode == "disaggregated" else "aggregated", + "slurm_launch_draft.sh", + ) + + # Get configs based on mode + env_config = get_env_config(config, runtime_mode) + bm_config = get_benchmark_config(config, benchmark_mode) + hardware_config = get_hardware_config( + config, + runtime_mode, + benchmark_mode, + test_name=select_pattern, + ) + + # Generate sbatch params + sbatch_lines = generate_sbatch_params(args, hardware_config, work_dir) + + # Generate srun args + srun_args_lines = generate_srun_args(args, runtime_mode, timestamp) + + # Generate pytest command + pytest_command, test_list_content, test_list_path = generate_pytest_command( + llm_src, work_dir, config_file_base_name, select_pattern, runtime_mode, benchmark_mode + ) + + # Write test list file + with open(test_list_path, "w") as f: + f.write(test_list_content + "\n") + + # Build script prefix lines + script_prefix_lines = sbatch_lines.copy() + + # Add export variables + script_prefix_lines.extend( + [ + f"export llmSrcNode='{llm_src}'", + f"export jobWorkspace='{work_dir}'", + f"export runScript='{run_sh}'", + f"export installScript='{install_sh}'", + f"export configYamlPath='{config_yaml}'", + f"export BUILD_WHEEL={'true' if args.build_wheel else 'false'}", + f"export INSTALL_MODE='{args.install_mode}'", + ] + ) + + nsys_prefix = "" + tllm_profile_start_stop = "" + ctx_tllm_profile_start_stop = "" + gen_tllm_profile_start_stop = "" + if args.capture_nsys: + if runtime_mode == "disaggregated": + nsys_output = f"{work_dir}/nsys.%q{{DISAGG_SERVING_TYPE}}.rank%q{{SLURM_PROCID}}" + else: + nsys_output = f"{work_dir}/nsys.rank%q{{SLURM_PROCID}}" + nsys_prefix = ( + "nsys profile" + " -t cuda,nvtx,python-gil" + " --sample cpu" + " --cuda-graph-trace node" + " -e TLLM_PROFILE_RECORD_GC=1,TLLM_LLMAPI_ENABLE_NVTX=1,TLLM_TORCH_PROFILE_TRACE=trace.json" + " --trace-fork-before-exec=true" + " -f true" + " --gpu-metrics-devices=none" + " -c cudaProfilerApi" + " --capture-range-end=stop" + " --export=sqlite" + f" -o {nsys_output}" + ) + tllm_profile_start_stop = args.nsys_start_stop + ctx_tllm_profile_start_stop = args.ctx_nsys_start_stop + gen_tllm_profile_start_stop = args.gen_nsys_start_stop + + pytest_common_vars = ( + f"LLM_ROOT='{llm_src}' " + f"LLM_BACKEND_ROOT='{llm_src}/triton_backend' " + f"LLM_MODELS_ROOT='{args.llm_models_root}' " + f"AGG_CONFIG_FOLDER='{AGG_CONFIG_FOLDER}' " + f"DISAGG_CONFIG_FOLDER='{DISAGG_CONFIG_FOLDER}' " + ) + llmapi_launch = f"{llm_src}/tensorrt_llm/llmapi/trtllm-llmapi-launch" + + # Add shared exports + script_prefix_lines.extend( + [ + f"export CAPTURE_NSYS={'true' if args.capture_nsys else 'false'}", + f'export NSYS_PREFIX="{nsys_prefix}"', + f'export LLM_API_LAUNCH="{llmapi_launch}"', + f'export PYTEST_COMMON_VARS="{pytest_common_vars}"', + f'export PYTEST_COMMAND="{pytest_command}"', + ] + ) + + server_env_vars = "" + benchmark_env_var = "" + if runtime_mode == "disaggregated": + # Build worker env vars (split into ctx and gen for role-specific settings) + common_worker_env_var = env_config.get("worker_env_var", "") + ctx_worker_env_vars = ( + f"TLLM_PROFILE_START_STOP='{ctx_tllm_profile_start_stop}' " + f"FLASHINFER_JIT_DIR=/tmp/flashinfer_jit_cache_\\${{SLURM_LOCALID}} " + f"HF_HOME=/tmp/hf_home " + f"{common_worker_env_var}" + ) + gen_worker_env_vars = ( + f"TLLM_PROFILE_START_STOP='{gen_tllm_profile_start_stop}' " + f"FLASHINFER_JIT_DIR=/tmp/flashinfer_jit_cache_\\${{SLURM_LOCALID}} " + f"HF_HOME=/tmp/hf_home " + f"{common_worker_env_var}" + ) + server_env_vars = env_config.get("server_env_var", "") + benchmark_env_var = env_config.get("benchmark_env_var", "") + # Handle gen only mode + if "gen_only_no_context" in bm_config.get("mode", ""): + gen_worker_env_vars = f"TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1 {gen_worker_env_vars}" + server_env_vars = f"TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1 {server_env_vars}" + script_prefix_lines.append("export TRTLLM_DISAGG_BENCHMARK_GEN_ONLY=1") + srun_args_lines.append("--container-env=TRTLLM_DISAGG_BENCHMARK_GEN_ONLY") + elif "gen_only" in bm_config.get("mode", ""): + concurrency = bm_config.get("concurrency", 1) + ctx_worker_env_vars = ( + f"TRTLLM_DISABLE_KV_CACHE_TRANSFER_OVERLAP=1 {ctx_worker_env_vars}" + ) + gen_worker_env_vars = ( + f"TRTLLM_DISABLE_KV_CACHE_TRANSFER_OVERLAP=1 " + f"TLLM_BENCHMARK_REQ_QUEUES_SIZE={concurrency} {gen_worker_env_vars}" + ) + + script_prefix_lines.extend( + [ + f'export CTX_WORKER_ENV_VARS="{ctx_worker_env_vars}"', + f'export GEN_WORKER_ENV_VARS="{gen_worker_env_vars}"', + f'export SERVER_ENV_VARS="{server_env_vars}"', + f'export BENCHMARK_ENV_VARS="{benchmark_env_var}"', + ( + 'export pytestCommandCTXWorker="unset UCX_TLS &&' + " $CTX_WORKER_ENV_VARS $PYTEST_COMMON_VARS" + " $NSYS_PREFIX $LLM_API_LAUNCH" + f' $PYTEST_COMMAND --junitxml={work_dir}/report.xml"' + ), + ( + 'export pytestCommandGENWorker="unset UCX_TLS &&' + " $GEN_WORKER_ENV_VARS $PYTEST_COMMON_VARS" + " $NSYS_PREFIX $LLM_API_LAUNCH" + f' $PYTEST_COMMAND --junitxml={work_dir}/report.xml"' + ), + 'export pytestCommandDisaggServer="$SERVER_ENV_VARS $PYTEST_COMMON_VARS $PYTEST_COMMAND"', + 'export pytestCommandBenchmark="$BENCHMARK_ENV_VARS $PYTEST_COMMON_VARS $PYTEST_COMMAND"', + f"export numCtxServers={hardware_config.get('num_ctx_servers', '')}", + f"export numGenServers={hardware_config.get('num_gen_servers', '')}", + f"export gpusPerNode={hardware_config.get('gpus_per_node', '')}", + f"export gpusPerCtxServer={hardware_config.get('gpus_per_ctx_server', '')}", + f"export gpusPerGenServer={hardware_config.get('gpus_per_gen_server', '')}", + f"export nodesPerCtxServer={hardware_config.get('nodes_per_ctx_server', '')}", + f"export nodesPerGenServer={hardware_config.get('nodes_per_gen_server', '')}", + f"export gpusPerNodePerCtxServer={hardware_config.get('gpus_per_node_per_ctx_server', '')}", + f"export gpusPerNodePerGenServer={hardware_config.get('gpus_per_node_per_gen_server', '')}", + f"export totalNodes={hardware_config.get('total_nodes', '')}", + f"export totalGpus={hardware_config.get('total_gpus', '')}", + ] + ) + + # Add srun args for disagg + srun_args_lines.extend( + [ + "--container-env=DISAGG_SERVING_TYPE", + "--container-env=pytestCommand", + ] + ) + else: + worker_env_vars = ( + f"TLLM_PROFILE_START_STOP='{tllm_profile_start_stop}' " + f"FLASHINFER_JIT_DIR=/tmp/flashinfer_jit_cache_\\${{SLURM_LOCALID}} " + f"HF_HOME=/tmp/hf_home " + ) + # Aggregated mode (including ctx_only) + script_prefix_lines.extend( + [ + f'export WORKER_ENV_VARS="{worker_env_vars}"', + ( + 'export pytestCommand="$WORKER_ENV_VARS $PYTEST_COMMON_VARS $NSYS_PREFIX $LLM_API_LAUNCH' + f' $PYTEST_COMMAND --junitxml={work_dir}/report.xml"' + ), + f"export gpusPerNode={hardware_config.get('gpus_per_node', '')}", + f"export gpusPerNodePerServer={hardware_config.get('gpus_per_node_per_server', '')}", + f"export totalNodes={hardware_config.get('total_nodes', '')}", + f"export totalGpus={hardware_config.get('total_gpus', '')}", + ] + ) + + # Remove whitespace lines + script_prefix_lines = remove_whitespace_lines(script_prefix_lines) + + # Format srun args + srun_args_lines = ["srunArgs=("] + [f' "{line}"' for line in srun_args_lines] + [")"] + srun_args = "\n".join(srun_args_lines) + + # Read draft launch script + with open(draft_launch_sh, "r") as f: + draft_launch_content = f.read() + draft_launch_lines = draft_launch_content.split("\n") + draft_launch_lines = remove_whitespace_lines(draft_launch_lines) + draft_launch_content = "\n".join(draft_launch_lines) + + # Combine and write launch script + script_prefix = "\n".join(script_prefix_lines) + final_script = f"{script_prefix}\n\n{srun_args}\n\n{draft_launch_content}" + + with open(launch_sh, "w") as f: + f.write(final_script) + + # Make scripts executable + os.chmod(launch_sh, 0o755) + for script_path in [run_sh, install_sh]: + if os.path.exists(script_path): + os.chmod(script_path, 0o755) + else: + print(f"Warning: Script not found, skipping chmod: {script_path}") + + print(f"\nLaunch script generated at: {launch_sh}") + print("\nTo submit the job, run:") + print(f" sbatch {launch_sh}") + + +if __name__ == "__main__": + main() diff --git a/jenkins/scripts/perf/perf_sanity_triage.py b/jenkins/scripts/perf/perf_sanity_triage.py index defe07106f5a..f588e0e5ea28 100644 --- a/jenkins/scripts/perf/perf_sanity_triage.py +++ b/jenkins/scripts/perf/perf_sanity_triage.py @@ -2,8 +2,10 @@ import argparse import json +import re import sys import time +from datetime import datetime, timezone from slack_sdk import WebClient from slack_sdk.errors import SlackApiError @@ -12,101 +14,284 @@ from open_search_db import OpenSearchDB QUERY_LOOKBACK_DAYS = 90 +LOOKBACK_JOBS = 30 MAX_QUERY_SIZE = 3000 -MAX_TEST_CASES_PER_MSG = 5 +MAX_TEST_CASES_PER_MSG = 4 POST_SLACK_MSG_RETRY_TIMES = 5 +# Comparison operators (order matters: >= before >, <= before <, != before =) +COMPARISON_OPERATORS = [">=", "<=", "!=", ">", "<", "="] +COMPARISON_ALLOWED_PREFIXES = ("d_", "l_") +COMPARISON_ALLOWED_FIELDS = ("ts_created",) -def query_regression_data(project_name): - """Query regression data from OpenSearch database.""" - last_days = QUERY_LOOKBACK_DAYS - must_clauses = [ - {"term": {"b_is_valid": True}}, - {"term": {"b_is_post_merge": True}}, - {"term": {"b_is_regression": True}}, - {"term": {"b_is_baseline": False}}, - { - "range": { - "ts_created": { - "gte": int(time.time() - 24 * 3600 * last_days) - // (24 * 3600) - * 24 - * 3600 - * 1000, - } - } - }, +def _timestamp_to_date(ts): + """Convert millisecond timestamp to YYYY/MM/DD format.""" + if ts == "N/A" or ts is None: + return "N/A" + try: + ts_int = int(ts) + # Convert milliseconds to seconds + dt = datetime.fromtimestamp(ts_int / 1000) + return dt.strftime("%Y/%m/%d") + except (ValueError, TypeError, OSError): + return str(ts) + + +def _parse_date_string(date_str): + """Convert date string like 'Feb 18, 2026 @ 22:32:02.960' to millisecond timestamp. + + All date strings are interpreted as UTC to ensure consistent timestamps + across different environments/timezones. + """ + date_str = date_str.strip() + # Try format: "Feb 18, 2026 @ 22:32:02.960" + try: + dt = datetime.strptime(date_str, "%b %d, %Y @ %H:%M:%S.%f") + dt = dt.replace(tzinfo=timezone.utc) + return int(dt.timestamp() * 1000) + except ValueError: + pass + # Try format: "Feb 18, 2026 @ 22:32:02" + try: + dt = datetime.strptime(date_str, "%b %d, %Y @ %H:%M:%S") + dt = dt.replace(tzinfo=timezone.utc) + return int(dt.timestamp() * 1000) + except ValueError: + pass + # Try format: "2026/02/18" + try: + dt = datetime.strptime(date_str, "%Y/%m/%d") + dt = dt.replace(tzinfo=timezone.utc) + return int(dt.timestamp() * 1000) + except ValueError: + pass + raise ValueError(f"Unable to parse date string: {date_str}") + + +def _can_use_comparison_operator(field_name): + """Check if a field can use comparison operators (>, <, >=, <=).""" + if field_name in COMPARISON_ALLOWED_FIELDS: + return True + if field_name.startswith(COMPARISON_ALLOWED_PREFIXES): + return True + return False + + +def _parse_value(value): + value = value.strip() + if len(value) >= 2 and ((value[0] == value[-1]) and value[0] in ("'", '"')): + return value[1:-1] + lower = value.lower() + if lower == "true": + return True + if lower == "false": + return False + if re.fullmatch(r"-?\d+", value): + return int(value) + if re.fullmatch(r"-?\d+\.\d+", value): + return float(value) + return value + + +def _split_and_clauses(text): + return [ + part.strip() for part in re.split(r"\s+AND\s+", text, flags=re.IGNORECASE) if part.strip() ] - json_data = { - "query": { - "bool": {"must": must_clauses}, - }, - "size": MAX_QUERY_SIZE, + +def _parse_assignments(text): + clauses = _split_and_clauses(text) + if not clauses: + return None, "No fields provided" + result = {} + for clause in clauses: + if "=" not in clause: + return None, f"Invalid clause (missing '='): {clause}" + key, value = clause.split("=", 1) + key = key.strip() + if not key: + return None, f"Invalid clause (empty field name): {clause}" + result[key] = _parse_value(value) + return result, None + + +def _parse_where_clauses(text): + """Parse WHERE clauses supporting =, >, <, >=, <= operators. + + Returns a list of tuples: (field_name, operator, value) + Only d_*, l_*, and ts_created fields can use comparison operators. + """ + clauses = _split_and_clauses(text) + if not clauses: + return None, "No fields provided" + + result = [] + for clause in clauses: + # Match: field_name value + # Using regex to find operator right after field name, avoiding false matches in values + m = re.match(r"^\s*(\w+)\s*(>=|<=|!=|>|<|=)\s*(.*)", clause) + if not m: + return None, f"Invalid clause (missing operator): {clause}" + + key = m.group(1).strip() + found_op = m.group(2) + value = _parse_value(m.group(3)) + + if not key: + return None, f"Invalid clause (empty field name): {clause}" + + # Check if comparison operator is allowed for this field + # != is allowed for all fields, but >, <, >=, <= are restricted + if found_op not in ("=", "!=") and not _can_use_comparison_operator(key): + return None, ( + f"Comparison operator '{found_op}' not allowed for field '{key}'. " + f"Only fields starting with 'd_', 'l_', or field 'ts_created' can use >, <, >=, <= operators." + ) + + # Convert date string to timestamp for ts_created + if key == "ts_created" and isinstance(value, str): + try: + value = _parse_date_string(value) + except ValueError as e: + return None, str(e) + + result.append((key, found_op, value)) + + return result, None + + +def _build_opensearch_clause(field, operator, value): + """Build OpenSearch query clause from field, operator, and value. + + Returns a tuple (clause_type, clause) where clause_type is "must" or "must_not". + """ + if operator == "=": + return ("must", {"term": {field: value}}) + + if operator == "!=": + return ("must_not", {"term": {field: value}}) + + op_map = { + ">": "gt", + "<": "lt", + ">=": "gte", + "<=": "lte", } - json_data = json.dumps(json_data) + return ("must", {"range": {field: {op_map[operator]: value}}}) + + +def parse_update_operation(operation): + match = re.match( + r"^\s*UPDATE\s+SET\s+(.+?)(?:\s+WHERE\s+(.+))?\s*$", operation, flags=re.IGNORECASE + ) + if not match: + return None, None, "Invalid UPDATE operation format" + set_text = match.group(1).strip() + where_text = match.group(2).strip() if match.group(2) else "" + set_values, error = _parse_assignments(set_text) + if error: + return None, None, f"Invalid SET clause: {error}" + where_clauses = [] + if match.group(2) is not None: + if not where_text: + return None, None, "Invalid WHERE clause: empty scope" + where_clauses, error = _parse_where_clauses(where_text) + if error: + return None, None, f"Invalid WHERE clause: {error}" + return set_values, where_clauses, None + + +def update_perf_data_fields(data_list, set_values): + updated_list = [] + for data in data_list: + updated_data = data.copy() + for key, value in set_values.items(): + updated_data[key] = value + updated_list.append(updated_data) + return updated_list - data_list = [] + +def post_perf_data(data_list, project_name): + if not data_list: + print(f"No data to post to {project_name}") + return False try: - res = OpenSearchDB.queryFromOpenSearchDB(json_data, project_name) - if res is None: - print(f"Failed to query from {project_name}, returned no response") - return None - payload = res.json().get("hits", {}).get("hits", []) - if len(payload) == 0: - print(f"No regression data found in {project_name}, returned empty list") - return [] - for hit in payload: - data_dict = hit.get("_source", {}) - data_dict["_id"] = hit.get("_id", "") - if data_dict["_id"] == "": - print(f"Failed to query from {project_name}, returned data with no _id") - return None - data_list.append(data_dict) - print(f"Successfully queried from {project_name}, queried {len(data_list)} entries") - return data_list + print(f"Ready to post {len(data_list)} data to {project_name}") + return OpenSearchDB.postToOpenSearchDB(data_list, project_name) except Exception as e: - print(f"Failed to query from {project_name}, returned error: {e}") - return None + print(f"Failed to post data to {project_name}, error: {e}") + return False -def get_regression_data_by_job_id(data_list, query_job_number): - """Returns a dict with job_id as key and list of regression data as value. +def get_regression_dict(data_list, query_job_number, lookback_job_number=LOOKBACK_JOBS): + """Returns a dict with job_id as key and list of regression tuples as value. + Each tuple is (test_case_name, gpu_type, runtime, history_regression_job_ids, data). Only returns the latest query_job_number jobs. """ if data_list is None or len(data_list) == 0: return {} # Group data by job_id - job_data_dict = {} + job_test_dict = {} for data in data_list: - job_id = data.get("s_job_id", "") - if job_id == "": + raw_job_id = data.get("s_job_id", "") + if raw_job_id == "": continue - if job_id not in job_data_dict: - job_data_dict[job_id] = [] - job_data_dict[job_id].append(data) - - # Sort job_ids by the latest ts_created in each group (descending) - def get_latest_timestamp(job_id): - timestamps = [d.get("ts_created", 0) for d in job_data_dict[job_id]] - return max(timestamps) if timestamps else 0 - - sorted_job_ids = sorted(job_data_dict.keys(), key=get_latest_timestamp, reverse=True) + try: + job_id = int(raw_job_id) + except (TypeError, ValueError): + continue + job_test_dict.setdefault(job_id, []).append(data) - # Only keep the latest query_job_number jobs - latest_job_ids = sorted_job_ids[:query_job_number] + if not job_test_dict: + return {} - result = {} + # Sort job_ids (descending: latest -> oldest) + sorted_job_id_list = sorted(job_test_dict.keys(), reverse=True) + + # Build (test_case_name, gpu_type, runtime) -> job_ids dict + test_job_dict = {} + for job_id, data_list in job_test_dict.items(): + for data in data_list: + test_case_name = data.get("s_test_case_name") or "" + gpu_type = data.get("s_gpu_type") or "" + runtime = data.get("s_runtime") or "" + if not test_case_name or not gpu_type or not runtime: + continue + key = (test_case_name, gpu_type, runtime) + test_job_dict.setdefault(key, set()).add(job_id) + + # Sort job ids for each test case (descending: latest -> oldest) + for key, job_id_set in list(test_job_dict.items()): + test_job_dict[key] = sorted(job_id_set, reverse=True) + + # Only keep the latest query_job_number jobs in the result + latest_job_ids = sorted_job_id_list[:query_job_number] + + regression_dict = {} for job_id in latest_job_ids: - result[job_id] = job_data_dict[job_id] - - return result - - -def process_regression_message(regression_dict): + entries = [] + for data in job_test_dict.get(job_id, []): + test_case_name = data.get("s_test_case_name") or "" + gpu_type = data.get("s_gpu_type") or "" + runtime = data.get("s_runtime") or "" + if not test_case_name or not gpu_type or not runtime: + continue + key = (test_case_name, gpu_type, runtime) + history_ids = test_job_dict.get(key, []) + lower_bound = job_id - lookback_job_number + 1 + history_regression_job_ids = [ + jid for jid in history_ids if lower_bound <= jid <= job_id + ] + entries.append((test_case_name, gpu_type, runtime, history_regression_job_ids, data)) + regression_dict[job_id] = entries + + return regression_dict + + +def split_regression_message(regression_dict): """Process regression data into message chunks. Returns a list of messages, each containing at most MAX_TEST_CASES_PER_MSG test cases. @@ -114,12 +299,17 @@ def process_regression_message(regression_dict): if not regression_dict: return [] - # Flatten all test cases into a list with (job_id, idx, data) tuples + # Flatten all test cases into a list with + # (job_id, idx, test_case_name, gpu_type, runtime, history_regression_job_ids, data) tuples all_test_cases = [] for job_id, data_list in regression_dict.items(): - sorted_data_list = sorted(data_list, key=lambda x: x.get("s_test_case_name", "")) - for idx, data in enumerate(sorted_data_list, start=1): - all_test_cases.append((job_id, idx, data)) + sorted_data_list = sorted(data_list, key=lambda x: x[0]) + for idx, (test_case_name, gpu_type, runtime, history_regression_job_ids, data) in enumerate( + sorted_data_list, start=1 + ): + all_test_cases.append( + (job_id, idx, test_case_name, gpu_type, runtime, history_regression_job_ids, data) + ) # Split into chunks of MAX_TEST_CASES_PER_MSG chunks = [] @@ -131,7 +321,15 @@ def process_regression_message(regression_dict): for chunk in chunks: msg_parts = [] current_job_id = None - for job_id, idx, data in chunk: + for ( + job_id, + idx, + test_case_name, + gpu_type, + runtime, + history_regression_job_ids, + data, + ) in chunk: # Add job header when switching to a new job_id if job_id != current_job_id: if msg_parts: @@ -140,12 +338,46 @@ def process_regression_message(regression_dict): msg_parts.append(job_header) current_job_id = job_id - test_case_name = data.get("s_test_case_name", "N/A") regression_info = data.get("s_regression_info", "N/A") + history_text = ( + ", ".join(str(jid) for jid in history_regression_job_ids) + if history_regression_job_ids + else "N/A" + ) msg_parts.append(f"*REGRESSION TEST CASE {idx}: {test_case_name}*\n") + msg_parts.append(f"*GPU: {gpu_type} Mode: {runtime}*\n") + msg_parts.append(f"*History Regression Post-Merge Job IDs: {history_text}*\n") + + # Parse regression_info to extract baseline info and metrics + baseline_date = "N/A" + baseline_branch = "N/A" + baseline_commit = "N/A" for part in regression_info.split(","): part = part.strip() - if part and "baseline_id" not in part: + if "baseline_date:" in part: + baseline_date = _timestamp_to_date(part.split(":", 1)[-1].strip()) + elif "baseline_branch:" in part: + baseline_branch = part.split(":", 1)[-1].strip() + elif "baseline_commit:" in part: + baseline_commit = part.split(":", 1)[-1].strip() + + # Get regression branch and commit from data + regression_date = _timestamp_to_date(data.get("ts_created", "N/A")) + regression_branch = data.get("s_branch", "N/A") + regression_commit = data.get("s_commit", "N/A") + + msg_parts.append( + f"*Baseline date, branch and commit: " + f"{baseline_date} {baseline_branch} {baseline_commit}*\n" + ) + msg_parts.append( + f"*Regression date, branch and commit: " + f"{regression_date} {regression_branch} {regression_commit}*\n" + ) + + for part in regression_info.split(","): + part = part.strip() + if part and "baseline_" not in part: msg_parts.append(f" {part}\n") msg = "".join(msg_parts).strip() @@ -235,14 +467,64 @@ def main(): print(f"Query Job Number: {args.query_job_number}") if args.operation == "SLACK BOT SENDS MESSAGE": - data_list = query_regression_data(args.project_name) + last_days = QUERY_LOOKBACK_DAYS + must_clauses = [ + {"term": {"b_is_valid": True}}, + {"term": {"b_is_post_merge": True}}, + {"term": {"b_is_regression": True}}, + {"term": {"b_is_baseline": False}}, + { + "range": { + "ts_created": { + "gte": int(time.time() - 24 * 3600 * last_days) + // (24 * 3600) + * 24 + * 3600 + * 1000, + } + } + }, + ] + data_list = OpenSearchDB.queryPerfDataFromOpenSearchDB( + args.project_name, must_clauses, size=MAX_QUERY_SIZE + ) if data_list is None: print("Failed to query regression data") return - regression_dict = get_regression_data_by_job_id(data_list, args.query_job_number) - messages = process_regression_message(regression_dict) + regression_dict = get_regression_dict(data_list, args.query_job_number) + messages = split_regression_message(regression_dict) send_regression_message(messages, args.channel_id, args.bot_token) + elif args.operation.strip().upper().startswith("UPDATE"): + set_values, where_clauses, error = parse_update_operation(args.operation) + if error: + print(error) + return + + must_clauses = [] + must_not_clauses = [] + for field, operator, value in where_clauses: + clause_type, clause = _build_opensearch_clause(field, operator, value) + if clause_type == "must": + must_clauses.append(clause) + else: + must_not_clauses.append(clause) + + data_list = OpenSearchDB.queryPerfDataFromOpenSearchDB( + args.project_name, must_clauses, size=MAX_QUERY_SIZE, must_not_clauses=must_not_clauses + ) + if data_list is None: + print("Failed to query data for update") + return + if len(data_list) == 0: + print("No data matched the update scope") + return + + updated_data_list = update_perf_data_fields(data_list, set_values) + if not post_perf_data(updated_data_list, args.project_name): + print("Failed to post updated data") + return + print(f"Updated {len(updated_data_list)} entries successfully") else: print(f"Unknown operation: {args.operation}") diff --git a/jenkins/scripts/perf/perf_utils.py b/jenkins/scripts/perf/perf_utils.py new file mode 100644 index 000000000000..aae00a35d86a --- /dev/null +++ b/jenkins/scripts/perf/perf_utils.py @@ -0,0 +1,1620 @@ +#!/usr/bin/env python3 +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Shared utilities for perf sanity scripts. + +Contains constants, regression detection algorithms, OpenSearch query helpers, +and HTML/SVG report generation functions used by test.py, get_pre_merge_html.py, +and perf_sanity_triage.py. +""" + +import json as _json +import math +import os +import sys +import time +from collections import defaultdict +from datetime import datetime +from html import escape as escape_html + +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) +from open_search_db import OpenSearchDB + +# --------------------------------------------------------------------------- +# Constants +# --------------------------------------------------------------------------- + +PERF_SANITY_PROJECT_NAME = "swdl-trtllm-infra-ci-prod-perf_sanity_info" +QUERY_LOOKBACK_DAYS = 90 +MAX_QUERY_SIZE = 9999 +DEFAULT_THRESHOLD = 0.05 + +CHART_METRICS = [ + "d_seq_throughput", + "d_token_throughput", + "d_total_token_throughput", + "d_user_throughput", +] + +# Only these 2 metrics determine the overall test-case classification. +CLASSIFICATION_METRICS = [ + "d_token_throughput", + "d_total_token_throughput", +] + +METRIC_LABELS = { + "d_seq_throughput": "Request Throughput (req/s)", + "d_token_throughput": "Output Token Throughput (tok/s)", + "d_total_token_throughput": "Total Token Throughput (tok/s)", + "d_user_throughput": "User Throughput (tok/s)", +} + +# Algorithm parameters +_STABILITY_CV_THRESHOLD = 0.03 # 3% +_REGRESSION_THRESHOLD = 0.05 # 5% +_ROLLING_WINDOW = 7 +_MIN_STABLE_SEGMENT = 7 +_MIN_CONFIRMATION_DAYS = 3 +_DIRECTION_CHANGE_THRESHOLD = 6 # per 30 days +_OUTLIER_ZSCORE = 2.0 + +# Curve type display +_CURVE_TYPE_COLORS = { + "no_regression": "#0d904f", + "sudden_drop": "#d93025", + "gradual_decline": "#e8710a", + "significant_fluctuation": "#7b1fa2", + "occasional_spike": "#c5a600", + "other_reasons": "#607d8b", +} + +_CURVE_TYPE_LABELS = { + "no_regression": "No Regression", + "sudden_drop": "Sudden Drop", + "gradual_decline": "Gradual Decline", + "significant_fluctuation": "Significant Fluctuation", + "occasional_spike": "Occasional Spike", + "other_reasons": "Other Reasons", +} + +# --------------------------------------------------------------------------- +# Timestamp / data utilities +# --------------------------------------------------------------------------- + +_TIME_FORMATS = [ + "%Y-%m-%dT%H:%M:%S.%fZ", + "%Y-%m-%dT%H:%M:%SZ", + "%Y-%m-%dT%H:%M:%S.%f", + "%Y-%m-%dT%H:%M:%S", + "%b %d, %Y @ %H:%M:%S.%f", +] + + +def _parse_timestamp(timestamp): + """Parse a timestamp value into a datetime object.""" + if isinstance(timestamp, (int, float)): + if timestamp > 1e12: + timestamp = timestamp / 1000 + return datetime.fromtimestamp(timestamp) + if isinstance(timestamp, datetime): + return timestamp + timestamp_str = str(timestamp) + for fmt in _TIME_FORMATS: + try: + return datetime.strptime(timestamp_str, fmt) + except ValueError: + continue + return datetime.fromtimestamp(0) + + +def _ts_to_date(ts): + """Convert a millisecond timestamp to a datetime.""" + try: + return datetime.fromtimestamp(int(ts) / 1000) + except (ValueError, TypeError, OSError): + return datetime.fromtimestamp(0) + + +def _extract_points(data_list, metric): + """Extract (datetime, float_value, data_dict) triples from data dicts.""" + points = [] + for d in data_list: + ts = d.get("ts_created") or d.get("@timestamp") + val = d.get(metric) + if ts is not None and val is not None: + try: + points.append((_ts_to_date(ts), float(val), d)) + except (ValueError, TypeError): + pass + points.sort(key=lambda p: p[0]) + return points + + +def _data_dict_to_json_attr(data_dict): + """Serialize a data dict to an HTML-safe JSON string for embedding in attributes.""" + return escape_html(_json.dumps(data_dict, default=str, ensure_ascii=True)) + + +# --------------------------------------------------------------------------- +# Baseline computation +# --------------------------------------------------------------------------- + + +def _daily_aggregate(points): + """Aggregate multiple data points on the same day to a single mean value. + + Args: + points: list of (datetime, float) or (datetime, float, data_dict) + tuples. + + Returns: + list of (date_str, float, [data_dicts]) triples sorted by date. + The third element is a list of original data dicts for that day + (empty list when input items have no third element). + """ + by_day = defaultdict(list) + entries = defaultdict(list) + for item in points: + dt, val = item[0], item[1] + day_key = dt.strftime("%Y-%m-%d") + by_day[day_key].append(val) + if len(item) > 2 and item[2] is not None: + entries[day_key].append(item[2]) + result = [] + for day in sorted(by_day): + vals = by_day[day] + result.append((day, sum(vals) / len(vals), entries[day])) + return result + + +def _rolling_smooth(values, window=3): + """Trailing rolling mean with same-length output. + + Early elements use fewer samples (i.e. the first element is itself, + the second is the mean of the first two, etc.). + """ + if not values: + return [] + smoothed = [] + for i in range(len(values)): + start = max(0, i - window + 1) + w = values[start : i + 1] + smoothed.append(sum(w) / len(w)) + return smoothed + + +def _percentile(values, p): + """Compute the p-th percentile with linear interpolation. + + Args: + values: non-empty list of floats. + p: percentile in [0, 100]. + """ + if not values: + return 0.0 + s = sorted(values) + k = (p / 100.0) * (len(s) - 1) + lo = int(k) + hi = min(lo + 1, len(s) - 1) + frac = k - lo + return s[lo] + frac * (s[hi] - s[lo]) + + +def get_baseline(grouped_data): + """Compute rolling-smooth + P95 baselines and daily data for all entries. + + For each (test_case, gpu_type) key and each metric, this function: + 1. Extracts data points as 3-tuples (datetime, float, data_dict). + 2. Aggregates to daily values preserving original data entries. + 3. Applies rolling smooth (window=3) to daily values. + 4. Computes P95 of the smoothed values as the baseline. + + Mutates ``grouped_data[key]`` to add: + "daily_data": {metric: {"dates": [...], "values": [...], + "entries": [[data_dicts], ...]}}, + "baselines": {metric: float}, + """ + for key, bucket in grouped_data.items(): + history_data = bucket["history_data"] + daily_data = {} + baselines = {} + for metric in CHART_METRICS: + points = _extract_points(history_data, metric) + daily = _daily_aggregate(points) + daily_dates = [d for d, _, _ in daily] + daily_vals = [v for _, v, _ in daily] + daily_entries = [e for _, _, e in daily] + + smoothed = _rolling_smooth(daily_vals, window=3) + baseline = _percentile(smoothed, 95) if smoothed else 0.0 + + daily_data[metric] = { + "dates": daily_dates, + "values": daily_vals, + "entries": daily_entries, + } + baselines[metric] = baseline + bucket["daily_data"] = daily_data + bucket["baselines"] = baselines + + +# --------------------------------------------------------------------------- +# Regression classification +# --------------------------------------------------------------------------- + + +def _extract_jump_commits(daily_entries, daily_dates, js_idx, je_idx): + """Extract commit and timestamp info at jump interval endpoints. + + Args: + daily_entries: list of lists of data_dicts (one list per day). + daily_dates: list of date strings corresponding to daily_entries. + js_idx: jump-start day index (left endpoint). + je_idx: jump-end day index (right endpoint). + + Returns: + {"left": {"s_commit": str, "timestamp": str}, + "right": {"s_commit": str, "timestamp": str}} + or None if data is unavailable. + """ + if not daily_entries or not daily_dates: + return None + js_idx = max(0, min(js_idx, len(daily_entries) - 1)) + je_idx = max(0, min(je_idx, len(daily_entries) - 1)) + + def _pick_last(entries_list): + """Pick the last chronological entry from a day's entries.""" + if not entries_list: + return None + best = entries_list[-1] + for e in entries_list: + ts_e = e.get("ts_created") or e.get("@timestamp", 0) + ts_b = best.get("ts_created") or best.get("@timestamp", 0) + if ts_e is not None and ts_b is not None and ts_e > ts_b: + best = e + commit = best.get("s_commit", "") + ts_raw = best.get("ts_created") or best.get("@timestamp", "") + if isinstance(ts_raw, (int, float)): + if ts_raw > 1e12: + ts_raw = ts_raw / 1000 + ts_str = datetime.fromtimestamp(ts_raw).strftime("%Y-%m-%d %H:%M") + else: + ts_str = str(ts_raw) + return {"s_commit": str(commit), "timestamp": ts_str} + + left = _pick_last(daily_entries[js_idx]) + right = _pick_last(daily_entries[je_idx]) + if left is None and right is None: + return None + return {"left": left, "right": right} + + +def _cv(values): + """Coefficient of variation (std / mean). Returns 0 if mean is 0.""" + if len(values) < 2: + return 0.0 + mean = sum(values) / len(values) + if mean == 0: + return 0.0 + variance = sum((v - mean) ** 2 for v in values) / len(values) + return math.sqrt(variance) / abs(mean) + + +def _is_stable(values, threshold=_STABILITY_CV_THRESHOLD): + """Check if CV < threshold.""" + return _cv(values) < threshold + + +def _rolling_stats(values, window=_ROLLING_WINDOW): + """Compute rolling means, rolling CVs, and direction change count. + + Returns: + (rolling_means, rolling_cvs, direction_changes) + """ + if len(values) < window: + return [], [], 0 + + rolling_means = [] + rolling_cvs = [] + for i in range(len(values) - window + 1): + w = values[i : i + window] + m = sum(w) / len(w) + rolling_means.append(m) + rolling_cvs.append(_cv(w)) + + direction_changes = 0 + for i in range(2, len(rolling_means)): + d_prev = rolling_means[i - 1] - rolling_means[i - 2] + d_curr = rolling_means[i] - rolling_means[i - 1] + if d_prev * d_curr < 0: + direction_changes += 1 + + return rolling_means, rolling_cvs, direction_changes + + +def _find_change_point(values, window=_ROLLING_WINDOW): + """Find the optimal split point using segmented approach (Phase 4). + + Returns: + (split_index, jump_start_index, jump_end_index) or None. + """ + n = len(values) + if n < 2 * window: + return None + + best_score = -1 + best_idx = -1 + eps = 1e-12 + + for i in range(window, n - window + 1): + left = values[:i] + right = values[i:] + left_mean = sum(left) / len(left) + right_mean = sum(right) / len(right) + left_var = sum((v - left_mean) ** 2 for v in left) / len(left) + right_var = sum((v - right_mean) ** 2 for v in right) / len(right) + score = (left_mean - right_mean) ** 2 / (left_var + right_var + eps) + if score > best_score: + best_score = score + best_idx = i + + if best_idx < 0: + return None + + pre_level = sum(values[:best_idx]) / best_idx + post_level = sum(values[best_idx:]) / (n - best_idx) + + if pre_level == post_level: + return best_idx, best_idx, best_idx + + threshold_start = pre_level - 0.2 * (pre_level - post_level) + threshold_end = pre_level - 0.8 * (pre_level - post_level) + + jump_start = best_idx + jump_end = best_idx + + if pre_level > post_level: + for j in range(n): + if values[j] < threshold_start: + jump_start = j + break + for j in range(n): + if values[j] < threshold_end: + jump_end = j + break + else: + for j in range(n): + if values[j] > threshold_start: + jump_start = j + break + for j in range(n): + if values[j] > threshold_end: + jump_end = j + break + + return best_idx, jump_start, jump_end + + +def _is_regression(daily_values, baseline, threshold=_REGRESSION_THRESHOLD): + """Step 1: Determine whether the metric shows a regression. + + A regression exists when the recent average drops more than + ``threshold`` compared to the baseline. + + Returns True if regression is detected, False otherwise. + """ + if not daily_values or baseline == 0: + return False + recent_count = min(5, max(3, len(daily_values))) + recent_avg = sum(daily_values[-recent_count:]) / recent_count + drop_ratio = (baseline - recent_avg) / baseline + return drop_ratio > threshold + + +def _classify_regression_type(daily_values): + """Step 2: Given that a regression exists, determine its subtype. + + Checks in priority order: + 1. Significant Fluctuation + 2. Occasional Spike + 3. Sudden Drop + 4. Gradual Decline + + If none of the four patterns match, falls back to ``"other_reasons"``. + + Returns (regression_type, jump_interval) where regression_type is one of + ``"significant_fluctuation"``, ``"occasional_spike"``, + ``"sudden_drop"``, ``"gradual_decline"``, ``"other_reasons"``. + """ + n_days = len(daily_values) + rolling_means, rolling_cvs, direction_changes = _rolling_stats(daily_values) + + # --- Significant Fluctuation --- + normalized_dir_changes = direction_changes * 30 / n_days if n_days > 0 else 0 + oscillation_windows = 0 + if rolling_means: + for i in range(len(rolling_means)): + w = daily_values[i : i + _ROLLING_WINDOW] + if w and max(w) > 0: + amp = (max(w) - min(w)) / max(w) + if amp > _REGRESSION_THRESHOLD: + oscillation_windows += 1 + has_long_stable = False + stable_run = 0 + for cv_val in rolling_cvs: + if cv_val < _STABILITY_CV_THRESHOLD: + stable_run += 1 + if stable_run >= 2 * _ROLLING_WINDOW: + has_long_stable = True + break + else: + stable_run = 0 + + if ( + normalized_dir_changes > _DIRECTION_CHANGE_THRESHOLD + and oscillation_windows > len(rolling_means) * 0.3 + and not has_long_stable + ): + return "significant_fluctuation", None + + # --- Occasional Spike --- + if n_days >= 3: + mean_val = sum(daily_values) / n_days + std_val = math.sqrt(sum((v - mean_val) ** 2 for v in daily_values) / n_days) + if std_val > 0: + outlier_indices = [ + i + for i, v in enumerate(daily_values) + if abs(v - mean_val) / std_val > _OUTLIER_ZSCORE + ] + else: + outlier_indices = [] + non_outlier_vals = [v for i, v in enumerate(daily_values) if i not in outlier_indices] + if len(outlier_indices) < 3 and non_outlier_vals and _is_stable(non_outlier_vals): + max_consecutive_low = 0 + consecutive = 0 + low_threshold = mean_val - _REGRESSION_THRESHOLD * mean_val + for v in daily_values: + if v < low_threshold: + consecutive += 1 + max_consecutive_low = max(max_consecutive_low, consecutive) + else: + consecutive = 0 + if max_consecutive_low < _MIN_CONFIRMATION_DAYS: + return "occasional_spike", None + + # --- Sudden Drop / Gradual Decline (via change-point analysis) --- + cp = _find_change_point(daily_values) + if cp is not None: + split_idx, jump_start, jump_end = cp + pre_segment = daily_values[:split_idx] + post_segment = daily_values[split_idx:] + + adj_left = max(0, jump_start - 1) + adj_right = jump_end + if adj_left >= adj_right: + adj_left = max(0, adj_right - 1) + if adj_left == adj_right: + adj_right = min(n_days - 1, adj_right + 1) + + if len(pre_segment) >= _MIN_STABLE_SEGMENT and len(post_segment) >= _MIN_CONFIRMATION_DAYS: + pre_stable = _is_stable(pre_segment) + post_stable = _is_stable(post_segment) + pre_mean = sum(pre_segment) / len(pre_segment) + post_mean = sum(post_segment) / len(post_segment) + + transition_width = abs(jump_end - jump_start) + 1 + shift = (pre_mean - post_mean) / pre_mean if pre_mean > 0 else 0 + + if ( + pre_stable + and post_stable + and shift > _REGRESSION_THRESHOLD + and transition_width <= 2 + ): + return "sudden_drop", (adj_left, adj_right) + + if ( + pre_stable + and post_stable + and shift > _REGRESSION_THRESHOLD + and transition_width > 2 + ): + decline_vals = daily_values[jump_start : jump_end + 1] + if len(decline_vals) >= 3: + x_vals = list(range(len(decline_vals))) + x_mean = sum(x_vals) / len(x_vals) + y_mean = sum(decline_vals) / len(decline_vals) + ss_xy = sum((x - x_mean) * (y - y_mean) for x, y in zip(x_vals, decline_vals)) + ss_xx = sum((x - x_mean) ** 2 for x in x_vals) + ss_yy = sum((y - y_mean) ** 2 for y in decline_vals) + if ss_xx > 0 and ss_yy > 0: + slope = ss_xy / ss_xx + r_squared = (ss_xy**2) / (ss_xx * ss_yy) + if slope < 0 and r_squared > 0.7: + return "gradual_decline", (adj_left, adj_right) + + return "other_reasons", (jump_start, jump_end) + + return "other_reasons", None + + +def classify_single_metric(daily_values, baseline, threshold=_REGRESSION_THRESHOLD): + """Two-step classification for one metric's time series. + + Step 1 -- Regression check: + Is the recent average more than ``threshold`` below the baseline? + If **no** -> ``"no_regression"``. + + Step 2 -- Regression subtype (only when Step 1 says *yes*): + Classify into one of ``"significant_fluctuation"``, + ``"occasional_spike"``, ``"sudden_drop"``, + ``"gradual_decline"``, or ``"other_reasons"``. + + Returns: + (curve_type, jump_interval) where jump_interval is + (start_index, end_index) or None. + """ + if not daily_values: + return "no_regression", None + + if not _is_regression(daily_values, baseline, threshold): + return "no_regression", None + + regression_type, jump_interval = _classify_regression_type(daily_values) + return regression_type, jump_interval + + +def _get_threshold_for_metric(baseline_data_list, metric): + """Get the pre-merge threshold for a metric from the latest baseline data. + + Looks for d_threshold_pre_merge_{metric_suffix} in the latest baseline + entry. Returns DEFAULT_THRESHOLD (5%) if not found. + """ + if not baseline_data_list: + return DEFAULT_THRESHOLD + latest_baseline = baseline_data_list[-1] + metric_suffix = metric[2:] # Remove "d_" prefix + threshold_key = f"d_threshold_pre_merge_{metric_suffix}" + if threshold_key in latest_baseline: + return latest_baseline[threshold_key] + return DEFAULT_THRESHOLD + + +def classify_test_case(grouped_data): + """Run classification on all metrics and aggregate results. + + Uses threshold from baseline data for each metric. Reads pre-computed + ``daily_data`` and ``baselines`` from each entry (populated by + :func:`get_baseline`) and stores classification results back into + ``grouped_data[key]``: + "curve_type": str (overall) + "per_metric_info": {metric: {"curve_type": str, + "jump_interval": (date_str, date_str) or None, + "jump_commits": {...} or None}} + """ + for key, bucket in grouped_data.items(): + daily_data = bucket.get("daily_data", {}) + baselines = bucket.get("baselines", {}) + baseline_data_list = bucket.get("baseline_data", []) + per_metric_results = {} + per_metric_info = {} + + for metric in CHART_METRICS: + md = daily_data.get(metric, {}) + daily_vals = md.get("values", []) + daily_dates = md.get("dates", []) + daily_entries = md.get("entries", []) + baseline = baselines.get(metric, 0.0) + + threshold = _get_threshold_for_metric(baseline_data_list, metric) + curve_type, jump = classify_single_metric(daily_vals, baseline, threshold) + per_metric_results[metric] = curve_type + + jump_dates = None + jump_commits = None + if jump is not None and daily_dates: + js, je = jump + js = max(0, min(js, len(daily_dates) - 1)) + je = max(0, min(je, len(daily_dates) - 1)) + jump_dates = (daily_dates[js], daily_dates[je]) + if curve_type in ("sudden_drop", "gradual_decline", "other_reasons"): + jump_commits = _extract_jump_commits(daily_entries, daily_dates, js, je) + + per_metric_info[metric] = { + "curve_type": curve_type, + "jump_interval": jump_dates, + "jump_commits": jump_commits, + } + + # Aggregate overall type using only CLASSIFICATION_METRICS. + # Both NR and OS are "transparent" (defer to the other metric). + # Priority: SF > OR > GD > SD > OS > NR + classification_types = [ + per_metric_results[m] for m in CLASSIFICATION_METRICS if m in per_metric_results + ] + + if not classification_types: + overall = "no_regression" + elif len(classification_types) == 1: + overall = classification_types[0] + else: + # 6x6 aggregation: merge two types via priority, where NR and + # OS are transparent (defer to the other curve's type). + _PRIORITY = { + "significant_fluctuation": 5, + "other_reasons": 4, + "gradual_decline": 3, + "sudden_drop": 2, + "occasional_spike": 1, + "no_regression": 0, + } + a, b = classification_types[0], classification_types[1] + pa, pb = _PRIORITY.get(a, 0), _PRIORITY.get(b, 0) + overall = a if pa >= pb else b + + bucket["curve_type"] = overall + bucket["per_metric_info"] = per_metric_info + + +# --------------------------------------------------------------------------- +# OpenSearch query + grouping +# --------------------------------------------------------------------------- + + +def get_history_data(extra_must_clauses=None): + """Query perf data from OpenSearch and group by (s_test_case_name, s_gpu_type). + + Queries both baseline and non-baseline data from the last + QUERY_LOOKBACK_DAYS days. Additional filters can be passed via + *extra_must_clauses*. + + Returns: + dict mapping (test_case, gpu_type) -> { + "history_data": [non-baseline entries sorted by time], + "baseline_data": [baseline entries sorted by time], + } + or None on query failure. + """ + must_clauses = [ + {"term": {"b_is_valid": True}}, + { + "range": { + "ts_created": { + "gte": int(time.time() - 24 * 3600 * QUERY_LOOKBACK_DAYS) + // (24 * 3600) + * 24 + * 3600 + * 1000, + } + } + }, + ] + if extra_must_clauses: + must_clauses.extend(extra_must_clauses) + + data_list = OpenSearchDB.queryPerfDataFromOpenSearchDB( + PERF_SANITY_PROJECT_NAME, must_clauses, size=MAX_QUERY_SIZE + ) + + if data_list is None: + return None + + groups = {} + for data in data_list: + key = ( + data.get("s_test_case_name", ""), + data.get("s_gpu_type", ""), + ) + groups.setdefault(key, {"history_data": [], "baseline_data": []}) + if data.get("b_is_baseline"): + groups[key]["baseline_data"].append(data) + else: + groups[key]["history_data"].append(data) + + for key, bucket in groups.items(): + bucket["history_data"] = sorted( + bucket["history_data"], + key=lambda d: _parse_timestamp(d.get("ts_created") or d.get("@timestamp", 0)), + ) + bucket["baseline_data"] = sorted( + bucket["baseline_data"], + key=lambda d: _parse_timestamp(d.get("ts_created") or d.get("@timestamp", 0)), + ) + + return groups + + +# --------------------------------------------------------------------------- +# SVG chart generation +# --------------------------------------------------------------------------- + +_SVG_WIDTH = 620 +_SVG_HEIGHT = 280 +_MARGIN = {"top": 30, "right": 20, "bottom": 55, "left": 75} +_PLOT_W = _SVG_WIDTH - _MARGIN["left"] - _MARGIN["right"] +_PLOT_H = _SVG_HEIGHT - _MARGIN["top"] - _MARGIN["bottom"] + + +def _generate_svg_chart( + history_points, + metric, + label, + new_points=None, + baseline_value=None, + threshold_line_value=None, + curve_type=None, + jump_interval=None, +): + """Return an SVG string for a single metric chart. + + Args: + history_points: list of (datetime, value) or (datetime, value, data_dict) + sorted by date. + metric: metric key string. + label: display label for the chart title. + new_points: optional list of (datetime, value) for new data (red dots). + baseline_value: optional float drawn as a horizontal dashed red line. + threshold_line_value: optional float drawn as a horizontal dashed + orange line (regression threshold). + curve_type: optional str -- the regression classification for this + metric (used for badge display). + jump_interval: optional (start_date_str, end_date_str) -- regression + window shading. + """ + all_values = [v for _, v, *_ in history_points if v is not None] + if new_points: + all_values.extend(v for _, v in new_points if v is not None) + if baseline_value is not None: + all_values.append(baseline_value) + if threshold_line_value is not None: + all_values.append(threshold_line_value) + + if not history_points and not new_points and baseline_value is None: + return f'
No data for {escape_html(label)}
' + if not all_values: + return ( + f'
No numeric data for {escape_html(label)}
' + ) + + min_val = min(all_values) + max_val = max(all_values) + val_range = max_val - min_val if max_val != min_val else 1.0 + min_val -= val_range * 0.05 + max_val += val_range * 0.05 + val_range = max_val - min_val + + dates = [d for d, *_ in history_points] + if new_points: + dates.extend(d for d, _ in new_points) + if not dates: + return ( + f'
No data points for {escape_html(label)}
' + ) + + min_ts = min(dates).timestamp() + max_ts = max(dates).timestamp() + ts_range = max_ts - min_ts if max_ts != min_ts else 1.0 + + def _x(dt): + return _MARGIN["left"] + (dt.timestamp() - min_ts) / ts_range * _PLOT_W + + def _x_date_str(date_str): + dt = datetime.strptime(date_str, "%Y-%m-%d") + ts = dt.timestamp() + ts = max(min_ts, min(ts, max_ts)) + return _MARGIN["left"] + (ts - min_ts) / ts_range * _PLOT_W + + def _y(v): + return _MARGIN["top"] + _PLOT_H - (v - min_val) / val_range * _PLOT_H + + svg = [ + f'' + ] + + # Grid lines (Y axis, 5 ticks) + for i in range(6): + v = min_val + val_range * i / 5 + y = _y(v) + svg.append( + f'' + ) + svg.append( + f'{v:.1f}' + ) + + # Jump interval shaded region + if jump_interval is not None: + j_start, j_end = jump_interval + jx1 = _x_date_str(j_start) + jx2 = _x_date_str(j_end) + if jx2 - jx1 < 4: + jx2 = jx1 + 4 + svg.append( + f'' + ) + svg.append( + f'' + ) + svg.append( + f'' + ) + + # Axes + svg.append( + f'' + ) + svg.append( + f'' + ) + + # X-axis date labels + unique_dates = sorted(set(dates)) + n_labels = min(6, len(unique_dates)) + if len(unique_dates) >= n_labels: + label_dates = unique_dates[:: max(1, len(unique_dates) // n_labels)][:n_labels] + else: + label_dates = unique_dates + for dt in label_dates: + x = _x(dt) + y_base = _MARGIN["top"] + _PLOT_H + svg.append( + f'{dt.strftime("%m/%d")}' + ) + + # Title with curve type badge + title_text = escape_html(label) + svg.append( + f'{title_text}' + ) + if curve_type and curve_type != "no_regression": + ct_color = _CURVE_TYPE_COLORS.get(curve_type, "#888") + ct_short = _CURVE_TYPE_LABELS.get(curve_type, curve_type) + badge_x = _SVG_WIDTH - _MARGIN["right"] - 4 + badge_y = _MARGIN["top"] - 16 + badge_text = ct_short + if jump_interval: + badge_text += f" [{jump_interval[0]} ~ {jump_interval[1]}]" + text_w = len(badge_text) * 5.5 + 10 + rx = badge_x - text_w + svg.append( + f'' + ) + svg.append( + f'{escape_html(badge_text)}' + ) + + # Baseline horizontal line (dashed red) + if baseline_value is not None: + by = _y(baseline_value) + svg.append( + f'' + ) + + # Threshold horizontal line (dashed orange) + if threshold_line_value is not None: + ty = _y(threshold_line_value) + svg.append( + f'' + ) + + # History line + dots (blue) + sorted_hist = sorted( + [(d, v, *rest) for d, v, *rest in history_points if v is not None], + key=lambda p: p[0], + ) + if len(sorted_hist) > 1: + path_d = " ".join( + f"{'M' if i == 0 else 'L'}{_x(d):.1f},{_y(v):.1f}" + for i, (d, v, *_) in enumerate(sorted_hist) + ) + svg.append(f'') + for item in sorted_hist: + d, v = item[0], item[1] + dd = item[2] if len(item) > 2 else None + if dd is not None: + json_attr = _data_dict_to_json_attr(dd) + svg.append( + f'' + f"{d.strftime('%Y-%m-%d %H:%M')} {v:.2f}" + ) + else: + svg.append(f'') + + # New data points (red) + if new_points: + for d, v in new_points: + if v is None: + continue + svg.append( + f'' + ) + + # Legend + legend_y = _MARGIN["top"] + _PLOT_H + 35 + legend_x = _MARGIN["left"] + 10 + svg.append(f'') + svg.append( + f'History' + ) + legend_x += 70 + if new_points: + svg.append(f'') + svg.append( + f'New' + ) + legend_x += 50 + if baseline_value is not None: + svg.append( + f'' + ) + svg.append( + f'Baseline ({baseline_value:.2f})' + ) + legend_x += 150 + if threshold_line_value is not None: + svg.append( + f'' + ) + svg.append( + f'Threshold ({threshold_line_value:.2f})' + ) + + svg.append("") + return "\n".join(svg) + + +# --------------------------------------------------------------------------- +# HTML report generation (post-merge dashboard) +# --------------------------------------------------------------------------- + + +def generate_post_merge_html(grouped_data, output_file): + """Generate a post-merge HTML dashboard from grouped perf data. + + This produces a full interactive report with three-way cascading filters + (GPU Type, Test Case, Curve Type), summary tables, and click-to-inspect + data-point popups. + """ + all_gpu_types = sorted(set(gpu for _, gpu in grouped_data.keys())) + all_test_cases = sorted(set(tc for tc, _ in grouped_data.keys())) + all_curve_types_set = set() + + sections = [] + section_tuples = [] + + for (test_case, gpu_type), bucket in sorted(grouped_data.items()): + history_data = bucket["history_data"] + curve_type = bucket.get("curve_type", "no_regression") + baselines = bucket.get("baselines", {}) + per_metric_info = bucket.get("per_metric_info", {}) + + all_curve_types_set.add(curve_type) + section_tuples.append((gpu_type, test_case, curve_type)) + + charts = [] + for metric in CHART_METRICS: + label = METRIC_LABELS.get(metric, metric) + hist_pts = _extract_points(history_data, metric) + baseline_val = baselines.get(metric) + m_info = per_metric_info.get(metric, {}) + charts.append( + _generate_svg_chart( + hist_pts, + metric, + label, + baseline_value=baseline_val, + curve_type=m_info.get("curve_type"), + jump_interval=m_info.get("jump_interval"), + ) + ) + + # Summary table + summary_rows = "" + if history_data: + latest = history_data[-1] + for metric in CHART_METRICS: + val = latest.get(metric) + bl_val = baselines.get(metric) + diff_str = "" + if val is not None and bl_val is not None and bl_val != 0: + diff_pct = (val - bl_val) / bl_val * 100 + color = "#0d904f" if diff_pct >= 0 else "#d93025" + diff_str = f' ({diff_pct:+.2f}%)' + val_str = f"{val:.2f}" if val is not None else "N/A" + bl_str = f"{bl_val:.2f}" if bl_val is not None else "N/A" + m_info = per_metric_info.get(metric, {}) + m_ct = m_info.get("curve_type", "no_regression") + m_ct_color = _CURVE_TYPE_COLORS.get(m_ct, "#888") + m_ct_label = _CURVE_TYPE_LABELS.get(m_ct, m_ct) + m_jump = m_info.get("jump_interval") + jump_str = "" + if m_jump: + jump_str = ( + f' ' + f"[{m_jump[0]} ~ {m_jump[1]}]" + ) + ct_cell = ( + f'{m_ct_label}' + f"{jump_str}" + ) + jc = m_info.get("jump_commits") + jl_cell = "" + jr_cell = "" + if jc: + left = jc.get("left") + right = jc.get("right") + if left and left.get("s_commit"): + short = left["s_commit"][:8] + ts = left.get("timestamp", "") + jl_cell = ( + f"{escape_html(short)}" + f'
' + f"{escape_html(ts)}" + ) + if right and right.get("s_commit"): + short = right["s_commit"][:8] + ts = right.get("timestamp", "") + jr_cell = ( + f"{escape_html(short)}" + f'
' + f"{escape_html(ts)}" + ) + summary_rows += ( + f"{METRIC_LABELS.get(metric, metric)}" + f"{val_str}{diff_str}" + f"{bl_str}" + f"{ct_cell}" + f"{jl_cell}" + f"{jr_cell}" + ) + + n_points = len(history_data) + ct_color = _CURVE_TYPE_COLORS.get(curve_type, "#888") + ct_label = _CURVE_TYPE_LABELS.get(curve_type, curve_type) + + header = escape_html(f"{test_case} [{gpu_type}]") + data_gpu = escape_html(gpu_type) + data_test = escape_html(test_case) + data_curve = escape_html(curve_type) + table_header = ( + "MetricLatest Value" + "Baseline (P95)Curve Type" + "Jump LeftJump Right" + ) + section = f""" +
+ {header} + {n_points} runs + {ct_label} + +
+ {"".join(charts)} +
+ { + "" + if not summary_rows + else f''' + + {table_header} + {summary_rows} +
+ ''' + } +
+ """ + sections.append(section) + + all_curve_types = sorted(all_curve_types_set) + + gpu_to_tests = {} + test_to_gpus = {} + for tc, gpu in grouped_data.keys(): + gpu_to_tests.setdefault(gpu, []) + if tc not in gpu_to_tests[gpu]: + gpu_to_tests[gpu].append(tc) + test_to_gpus.setdefault(tc, []) + if gpu not in test_to_gpus[tc]: + test_to_gpus[tc].append(gpu) + for k in gpu_to_tests: + gpu_to_tests[k].sort() + for k in test_to_gpus: + test_to_gpus[k].sort() + + triples_json = _json.dumps(section_tuples) + + gpu_chips = [ + '' + ] + for gpu in all_gpu_types: + gpu_chips.append( + f'' + ) + + test_chips = [ + '' + ] + for tc in all_test_cases: + test_chips.append( + f'' + ) + + curve_chips = [ + '' + ] + for ct in all_curve_types: + ct_color = _CURVE_TYPE_COLORS.get(ct, "#888") + ct_label = _CURVE_TYPE_LABELS.get(ct, ct) + curve_chips.append( + f'" + ) + + html = f""" + + + + Perf Sanity History Dashboard + + + +

Perf Sanity History Dashboard

+

+ {len(grouped_data)} test case(s) · + Lookback: {QUERY_LOOKBACK_DAYS} days · + Generated: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")} +

+ +
+

GPU Type

+
+ {"".join(gpu_chips)} +
+

Test Case

+
+ {"".join(test_chips)} +
+

Curve Type

+
+ {"".join(curve_chips)} +
+
+
+ +
+ + +
+ +
+ {"".join(sections)} +
+ + + + +""" + with open(output_file, "w", encoding="utf-8") as f: + f.write(html) + print(f"Generated perf history report with {len(grouped_data)} test cases: {output_file}") diff --git a/tests/integration/defs/perf/open_search_db_utils.py b/tests/integration/defs/perf/open_search_db_utils.py index cfc7cd62d3a7..9b7f7895ace8 100644 --- a/tests/integration/defs/perf/open_search_db_utils.py +++ b/tests/integration/defs/perf/open_search_db_utils.py @@ -22,6 +22,7 @@ import time from datetime import datetime +import yaml from defs.trt_test_alternative import print_info, print_warning _project_root = os.path.abspath( @@ -224,93 +225,6 @@ def get_common_values(new_data_dict, match_keys): return common_values_dict -def query_history_data(common_values_dict): - """ - Query post-merge data with common values to narrow down scope. - """ - # Query data from the last 90 days - last_days = QUERY_LOOKBACK_DAYS - - # Build must clauses with base filters - must_clauses = [ - { - "term": { - "b_is_valid": True - } - }, - { - "term": { - "b_is_post_merge": True - } - }, - { - "term": { - "b_is_regression": False - } - }, - { - "range": { - "ts_created": { - "gte": - int(time.time() - 24 * 3600 * last_days) // (24 * 3600) * - 24 * 3600 * 1000, - } - } - }, - ] - - # Add common values as term filters to narrow down the query - for key, value in common_values_dict.items(): - must_clauses.append({"term": {key: value}}) - - json_data = { - "query": { - "bool": { - "must": must_clauses - }, - }, - "size": MAX_QUERY_SIZE, - } - json_data = json.dumps(json_data) - - data_list = [] - try: - res = OpenSearchDB.queryFromOpenSearchDB(json_data, - TEST_INFO_PROJECT_NAME) - if res is None: - # No response from database, return None - print_info( - f"Failed to query from {TEST_INFO_PROJECT_NAME}, returned no response" - ) - return None - payload = res.json().get("hits", {}).get("hits", []) - if len(payload) == 0: - # No history data found in database, return empty list - print_info( - f"No history data found in {TEST_INFO_PROJECT_NAME}, returned empty list" - ) - return [] - for hit in payload: - data_dict = hit.get("_source", {}) - data_dict["_id"] = hit.get("_id", "") - if data_dict["_id"] == "": - print_info( - f"Failed to query from {TEST_INFO_PROJECT_NAME}, returned data with no _id" - ) - # Invalid data, return None - return None - data_list.append(data_dict) - print_info( - f"Successfully queried from {TEST_INFO_PROJECT_NAME}, queried {len(data_list)} entries" - ) - return data_list - except Exception as e: - print_info( - f"Failed to query from {TEST_INFO_PROJECT_NAME}, returned error: {e}" - ) - return None - - def match(history_data, new_data, match_keys): """ Check if the server and client config of history data match the new data @@ -329,16 +243,76 @@ def is_empty(value): return True -def calculate_best_perf_result(history_data_list, new_data): +def _rolling_smooth(values, window=3): + """Trailing rolling mean with same-length output. + + Early elements use fewer samples (i.e. the first element is itself, + the second is the mean of the first two, etc.). """ - Get the best performance metrics from history data and new data + if not values: + return [] + smoothed = [] + for i in range(len(values)): + start = max(0, i - window + 1) + w = values[start:i + 1] + smoothed.append(sum(w) / len(w)) + return smoothed + + +def _percentile(values, p): + """Compute the p-th percentile with linear interpolation.""" + if not values: + return 0.0 + s = sorted(values) + k = (p / 100.0) * (len(s) - 1) + lo = int(k) + hi = min(lo + 1, len(s) - 1) + frac = k - lo + return s[lo] + frac * (s[hi] - s[lo]) + + +def _daily_aggregate_values(data_list, metric): + """Aggregate multiple data points on the same day to a single mean value. + + Returns a list of daily-aggregated metric values sorted by date. + """ + by_day = {} + for data in data_list: + if data.get("b_is_baseline"): + continue + val = data.get(metric) + if val is None: + continue + ts = data.get("ts_created") or data.get("@timestamp") + if ts is None: + continue + if isinstance(ts, (int, float)): + if ts > 1e12: + ts = ts / 1000 + day_key = datetime.fromtimestamp(ts).strftime("%Y-%m-%d") + elif isinstance(ts, datetime): + day_key = ts.strftime("%Y-%m-%d") + else: + day_key = str(ts)[:10] + by_day.setdefault(day_key, []).append(val) + result = [] + for day in sorted(by_day): + vals = by_day[day] + result.append(sum(vals) / len(vals)) + return result + + +def calculate_baseline_metrics(history_data_list, new_data): + """Calculate baseline metrics using rolling smooth + percentile algorithm. + + For each metric, aggregates data to daily values, applies a trailing + rolling mean (window=3), then takes: + - P95 for MAXIMIZE_METRICS (larger is better, e.g. throughput) + - P5 for MINIMIZE_METRICS (smaller is better, e.g. latency) """ - # Combine history data and new data all_data = [] if history_data_list: all_data.extend(history_data_list) - - # Handle new_data as either a single dict or list if isinstance(new_data, list): all_data.extend(new_data) elif new_data: @@ -347,35 +321,18 @@ def calculate_best_perf_result(history_data_list, new_data): if not all_data: return {} - best_metrics = {} - - # Calculate best values for maximize metrics - for metric in MAXIMIZE_METRICS: - values = [] - for data in all_data: - # Skip baseline data - if data.get("b_is_baseline") and data.get("b_is_baseline") == True: - continue - if metric not in data: - continue - values.append(data.get(metric)) - if values: - best_metrics[metric] = max(values) - - # Calculate best values for minimize metrics - for metric in MINIMIZE_METRICS: - values = [] - for data in all_data: - # Skip baseline data - if data.get("b_is_baseline") and data.get("b_is_baseline") == True: - continue - if metric not in data: - continue - values.append(data.get(metric)) - if values: - best_metrics[metric] = min(values) + baseline_metrics = {} + for metric in MAXIMIZE_METRICS + MINIMIZE_METRICS: + daily_vals = _daily_aggregate_values(all_data, metric) + if not daily_vals: + continue + smoothed = _rolling_smooth(daily_vals, window=3) + if metric in MAXIMIZE_METRICS: + baseline_metrics[metric] = _percentile(smoothed, 95) + else: + baseline_metrics[metric] = _percentile(smoothed, 5) - return best_metrics + return baseline_metrics def get_history_data(new_data_dict, match_keys, common_values_dict): @@ -423,7 +380,32 @@ def parse_timestamp(timestamp): cmd_idxs = new_data_dict.keys() history_data_list = None if cmd_idxs: - history_data_list = query_history_data(common_values_dict) + last_days = QUERY_LOOKBACK_DAYS + must_clauses = [ + { + "term": { + "b_is_valid": True + } + }, + { + "term": { + "b_is_post_merge": True + } + }, + { + "range": { + "ts_created": { + "gte": + int(time.time() - 24 * 3600 * last_days) // + (24 * 3600) * 24 * 3600 * 1000, + } + } + }, + ] + for key, value in common_values_dict.items(): + must_clauses.append({"term": {key: value}}) + history_data_list = OpenSearchDB.queryPerfDataFromOpenSearchDB( + TEST_INFO_PROJECT_NAME, must_clauses, size=MAX_QUERY_SIZE) # If query_history_data returned None, it means network failure if history_data_list is None: @@ -504,9 +486,12 @@ def prepare_regressive_test_cases(history_baseline_dict, new_data_dict): continue is_post_merge = new_data.get("b_is_post_merge", False) - baseline_id = history_baseline.get("_id", "") - - info_parts = [f"baseline_id: {baseline_id}"] + info_parts = [ + f"baseline_id: {history_baseline.get('_id', '')}", + f"baseline_branch: {history_baseline.get('s_branch', '')}", + f"baseline_commit: {history_baseline.get('s_commit', '')}", + f"baseline_date: {history_baseline.get('ts_created', '')}", + ] regressive_metrics = [] # Check all metrics and build info string for metric in MAXIMIZE_METRICS + MINIMIZE_METRICS: @@ -563,8 +548,8 @@ def prepare_baseline_data(history_baseline_dict, history_data_dict, cmd_idxs = new_data_dict.keys() # Find the best history post-merge data for each cmd for cmd_idx in cmd_idxs: - # Calculate best metrics from history post-merge data and new data - best_metrics = calculate_best_perf_result(history_data_dict[cmd_idx], + # Calculate baseline metrics using rolling smooth + P95 algorithm + best_metrics = calculate_baseline_metrics(history_data_dict[cmd_idx], new_data_dict[cmd_idx]) # Create new_baseline_data from new_data_dict and set b_is_baseline @@ -643,82 +628,115 @@ def _get_metric_keys(): return metric_keys -def _print_regression_data(data, print_func=None): - """ - Print regression info and config. +def generate_perf_yaml(new_data_dict, output_dir=None): """ - if print_func is None: - print_func = print_info - - if "s_regression_info" in data: - print_func("=== Regression Info ===") - for item in data["s_regression_info"].split(","): - print_func(item.strip()) + Save new perf data entries to perf_data.yaml for post-processing. - metric_keys = _get_metric_keys() - - print_func("\n=== Config ===") - config_keys = sorted([key for key in data.keys() if key not in metric_keys]) - for key in config_keys: - if key == "s_regression_info": - continue - value = data[key] - print_func(f'"{key}": {value}') + Each entry in the output list is a dict with: + - "new_data": the new perf data dict + """ + all_entries = [] + for cmd_idx, new_data in new_data_dict.items(): + entry = {"new_data": new_data} + all_entries.append(entry) + + if output_dir is not None and len(all_entries) > 0: + perf_data_file = os.path.join(output_dir, "perf_data.yaml") + with open(perf_data_file, 'w') as f: + yaml.dump(all_entries, f, default_flow_style=False) + print_info( + f"Saved {len(all_entries)} perf data entries to {perf_data_file}") + elif len(all_entries) == 0: + print_info("No perf data to save.") -def check_perf_regression(new_data_dict, fail_on_regression=False): - """ - Check performance regression by printing regression data from new_data_dict. - If fail_on_regression is True, raises RuntimeError when regressions are found. - (This is a temporary feature to fail regression tests. We are observing the stability and will fail them by default soon.) - """ - # Filter regression data from new_data_dict - regressive_data_list = [ - data for data in new_data_dict.values() - if data.get("b_is_regression", False) - ] - # Split regression data into post-merge and pre-merge - post_merge_regressions = [ - data for data in regressive_data_list - if data.get("b_is_post_merge", False) - ] - pre_merge_regressions = [ - data for data in regressive_data_list - if not data.get("b_is_post_merge", False) - ] - - # Print pre-merge regression data with print_warning - if len(pre_merge_regressions) > 0: - print_warning( - f"Found {len(pre_merge_regressions)} pre-merge perf regression data" - ) - for i, data in enumerate(pre_merge_regressions): - print_warning(f"\n{'=' * 60}") - print_warning(f"Pre-merge Regression Data #{i + 1}") - print_warning("=" * 60) - _print_regression_data(data, print_func=print_warning) - - if fail_on_regression: - raise RuntimeError( - f"Found {len(pre_merge_regressions)} pre-merge perf regression data" - ) - - # Print post-merge regression data with print_warning - if len(post_merge_regressions) > 0: - print_warning( - f"Found {len(post_merge_regressions)} post-merge perf regression data" - ) - for i, data in enumerate(post_merge_regressions): - print_warning(f"\n{'=' * 60}") - print_warning(f"Post-merge Regression Data #{i + 1}") - print_warning("=" * 60) - _print_regression_data(data, print_func=print_warning) - - if fail_on_regression: - raise RuntimeError( - f"Found {len(post_merge_regressions)} post-merge perf regression data" - ) - - # Print summary if no regressions - if len(regressive_data_list) == 0: - print_info("No regression data found.") +# def _print_regression_data(data, print_func=None): +# """ +# Print regression info and config. +# """ +# if print_func is None: +# print_func = print_info +# +# if "s_regression_info" in data: +# print_func("=== Regression Info ===") +# for item in data["s_regression_info"].split(","): +# print_func(item.strip()) +# +# metric_keys = _get_metric_keys() +# +# print_func("\n=== Config ===") +# config_keys = sorted([key for key in data.keys() if key not in metric_keys]) +# for key in config_keys: +# if key == "s_regression_info": +# continue +# value = data[key] +# print_func(f'"{key}": {value}') + +# def check_perf_regression(new_data_dict, +# fail_on_regression=False, +# output_dir=None): +# """ +# Check performance regression by printing regression data from new_data_dict. +# If fail_on_regression is True, raises RuntimeError when regressions are found. +# (This is a temporary feature to fail regression tests. We are observing the stability and will fail them by default soon.) +# If output_dir is provided, saves regression data to regression_data.yaml. +# """ +# # Filter regression data from new_data_dict +# regressive_data_list = [ +# data for data in new_data_dict.values() +# if data.get("b_is_regression", False) +# ] +# # Split regression data into post-merge and pre-merge +# post_merge_regressions = [ +# data for data in regressive_data_list +# if data.get("b_is_post_merge", False) +# ] +# pre_merge_regressions = [ +# data for data in regressive_data_list +# if not data.get("b_is_post_merge", False) +# ] +# +# # Save regression data to yaml file if output_dir is provided +# if output_dir is not None and len(regressive_data_list) > 0: +# regression_data_file = os.path.join(output_dir, "regression_data.yaml") +# with open(regression_data_file, 'w') as f: +# yaml.dump(regressive_data_list, f, default_flow_style=False) +# print_info( +# f"Saved {len(regressive_data_list)} regression data to {regression_data_file}" +# ) +# +# # Print pre-merge regression data with print_warning +# if len(pre_merge_regressions) > 0: +# print_warning( +# f"Found {len(pre_merge_regressions)} pre-merge perf regression data" +# ) +# for i, data in enumerate(pre_merge_regressions): +# print_warning(f"\n{'=' * 60}") +# print_warning(f"Pre-merge Regression Data #{i + 1}") +# print_warning("=" * 60) +# _print_regression_data(data, print_func=print_warning) +# +# if fail_on_regression: +# raise RuntimeError( +# f"Found {len(pre_merge_regressions)} pre-merge perf regression data" +# ) +# +# # Print post-merge regression data with print_warning +# if len(post_merge_regressions) > 0: +# print_warning( +# f"Found {len(post_merge_regressions)} post-merge perf regression data" +# ) +# for i, data in enumerate(post_merge_regressions): +# print_warning(f"\n{'=' * 60}") +# print_warning(f"Post-merge Regression Data #{i + 1}") +# print_warning("=" * 60) +# _print_regression_data(data, print_func=print_warning) +# +# if fail_on_regression: +# raise RuntimeError( +# f"Found {len(post_merge_regressions)} post-merge perf regression data" +# ) +# +# # Print summary if no regressions +# if len(regressive_data_list) == 0: +# print_info("No regression data found.") diff --git a/tests/integration/defs/perf/test_perf_sanity.py b/tests/integration/defs/perf/test_perf_sanity.py index 6b1b9124e278..161eb4dd5509 100644 --- a/tests/integration/defs/perf/test_perf_sanity.py +++ b/tests/integration/defs/perf/test_perf_sanity.py @@ -14,10 +14,8 @@ # limitations under the License. """TensorRT LLM perf sanity tests.""" -import contextlib import copy import glob -import io import os import re import socket @@ -26,18 +24,18 @@ from typing import Dict, List, NamedTuple, Optional, Tuple import pytest -import requests import yaml +from test_common.error_utils import report_error from test_common.http_utils import wait_for_endpoint_ready -from defs.trt_test_alternative import print_error, print_info +from defs.trt_test_alternative import print_info from tensorrt_llm._utils import get_free_port from ..conftest import get_llm_root, llm_models_root from .open_search_db_utils import ( SCENARIO_MATCH_FIELDS, add_id, - check_perf_regression, + generate_perf_yaml, get_common_values, get_history_data, get_job_info, @@ -45,7 +43,6 @@ prepare_baseline_data, prepare_regressive_test_cases, ) -from .utils import collect_and_clean_myelin_time # Model PATH of local dir synced from internal LLM models repo MODEL_PATH_DICT = { @@ -54,18 +51,25 @@ "deepseek_r1_0528_fp8": "DeepSeek-R1/DeepSeek-R1-0528/", "deepseek_r1_0528_fp4": "DeepSeek-R1/DeepSeek-R1-0528-FP4/", "deepseek_r1_0528_fp4_v2": "DeepSeek-R1/DeepSeek-R1-0528-FP4-v2/", + "deepseek_v32_fp4": "DeepSeek-V3.2-Exp-FP4-v2", "gpt_oss_120b_fp4": "gpt_oss/gpt-oss-120b", + "k2_thinking_fp4": "Kimi-K2-Thinking-NVFP4", + "qwen3_235b_a22b_fp4": "Qwen3/saved_models_Qwen3-235B-A22B_nvfp4_hf", # Qwen3-235B-A22B-FP4 } -SUPPORTED_GPU_TYPE = [ - "H200", - "B200", - "B300", - "GB200", - "GB300", -] +SUPPORTED_GPU_MAPPING = { + "GB200": "gb200", + "GB300": "gb300", + "B200": "b200", + "B300": "b300", + "H200": "h200", +} -DEFAULT_TIMEOUT = 7200 +DEFAULT_TIMEOUT = 5400 +AGG_CONFIG_FOLDER = os.environ.get("AGG_CONFIG_FOLDER", "tests/scripts/perf-sanity/aggregated") +DISAGG_CONFIG_FOLDER = os.environ.get( + "DISAGG_CONFIG_FOLDER", "tests/scripts/perf-sanity/disaggregated" +) # Regex patterns for parsing benchmark output metrics # Key is the metric name used in database (e.g., "mean_e2el", "seq_throughput") @@ -96,9 +100,20 @@ def get_model_dir(model_name: str) -> str: return "" -def get_dataset_path() -> str: - """Get dataset path for benchmark.""" - return os.path.join(llm_models_root(), "datasets", "ShareGPT_V3_unfiltered_cleaned_split.json") +def get_dataset_dir(dataset_file: Optional[str]) -> str: + """Get dataset directory path from dataset file.""" + if not dataset_file or dataset_file == "": + return "" + + # return os.path.join(llm_models_root(), "datasets", "ShareGPT_V3_unfiltered_cleaned_split.json") + llm_models_path = os.path.join(llm_models_root(), dataset_file) + if os.path.exists(llm_models_path): + return llm_models_path + elif os.path.exists(dataset_file): + return dataset_file + else: + print_info(f"Dataset file not found in {llm_models_path} and {dataset_file}") + return "" def to_env_dict(env_vars: str) -> Dict[str, str]: @@ -140,6 +155,7 @@ def __init__(self, server_config_data: dict, env_vars: str = ""): self.disable_overlap_scheduler = server_config_data.get("disable_overlap_scheduler", False) self.num_postprocess_workers = server_config_data.get("num_postprocess_workers", 0) self.stream_interval = server_config_data.get("stream_interval", 10) + self.print_iter_log = server_config_data.get("print_iter_log", False) self.attn_backend = server_config_data.get("attn_backend", "TRTLLM") self.enable_chunked_prefill = server_config_data.get("enable_chunked_prefill", False) self.enable_attention_dp = server_config_data.get("enable_attention_dp", False) @@ -212,6 +228,7 @@ def __init__(self, server_config_data: dict, env_vars: str = ""): self.eagle3_layers_to_capture = [] self.max_draft_len = speculative_config.get("max_draft_len", 0) self.speculative_model = speculative_config.get("speculative_model", "") + self.eagle3_one_model = speculative_config.get("eagle3_one_model", False) # match_mode: "config" (default) or "scenario" self.match_mode = server_config_data.get("match_mode", "config") @@ -269,15 +286,11 @@ def to_match_keys(self) -> List[str]: "l_gpus_per_node", "l_max_batch_size", "b_disable_overlap_scheduler", - "l_num_postprocess_workers", - "s_attn_backend", "b_enable_chunked_prefill", "b_enable_attention_dp", "b_enable_lm_head_tp_in_adp", # attention_dp_config "b_attention_dp_balance", - # moe_config - "s_moe_backend", # cuda_graph_config "b_enable_cuda_graph", # kv_cache_config @@ -339,6 +352,7 @@ def to_db_data(self) -> dict: "s_eagle3_layers_to_capture": ",".join(map(str, self.eagle3_layers_to_capture)), "l_max_draft_len": self.max_draft_len, "s_speculative_model_dir": self.speculative_model, + "b_eagle3_one_model": self.eagle3_one_model, "s_server_log_link": "", "s_server_env_var": self.env_vars, } @@ -365,7 +379,12 @@ def generate_extra_llm_api_config(self) -> str: class ClientConfig: """Configurations of benchmark client.""" - def __init__(self, client_config_data: dict, model_name: str, env_vars: str = ""): + def __init__( + self, + client_config_data: dict, + model_name: str, + env_vars: str = "", + ): self.model_name = model_name self.concurrency = client_config_data.get("concurrency", 1) self.iterations = client_config_data.get("iterations", 1) @@ -375,7 +394,9 @@ def __init__(self, client_config_data: dict, model_name: str, env_vars: str = "" self.backend = client_config_data.get("backend", "openai") self.use_chat_template = client_config_data.get("use_chat_template", False) self.streaming = client_config_data.get("streaming", True) + self.trust_remote_code = client_config_data.get("trust_remote_code", True) self.model_path = "" + self.dataset_file = client_config_data.get("dataset_file", "") self.env_vars = env_vars # Generate default name if not provided @@ -387,7 +408,7 @@ def to_cmd(self) -> List[str]: """Generate benchmark command.""" model_dir = get_model_dir(self.model_name) self.model_path = model_dir if os.path.exists(model_dir) else self.model_name - dataset_path = get_dataset_path() + dataset_path = get_dataset_dir(self.dataset_file) benchmark_cmd = [ "python", "-m", @@ -396,27 +417,36 @@ def to_cmd(self) -> List[str]: self.model_path, "--tokenizer", self.model_path, - "--dataset-name", - "random", - "--random-ids", "--num-prompts", str(self.concurrency * self.iterations), "--max-concurrency", str(self.concurrency), - "--random-input-len", - str(self.isl), - "--random-output-len", - str(self.osl), - "--random-range-ratio", - str(self.random_range_ratio), - "--trust-remote-code", "--ignore-eos", + "--no-test-input", "--percentile-metrics", "ttft,tpot,itl,e2el", ] - if dataset_path and os.path.exists(dataset_path): + if dataset_path: + benchmark_cmd.append("--dataset-name") + benchmark_cmd.append("trtllm_custom") benchmark_cmd.append("--dataset-path") benchmark_cmd.append(dataset_path) + print_info(f"Dataset: {dataset_path} exists. Use trtllm_custom dataset for benchmark.") + else: + benchmark_cmd.append("--dataset-name") + benchmark_cmd.append("random") + benchmark_cmd.append("--random-ids") + benchmark_cmd.append("--tokenize-on-client") + benchmark_cmd.append("--random-input-len") + benchmark_cmd.append(str(self.isl)) + benchmark_cmd.append("--random-output-len") + benchmark_cmd.append(str(self.osl)) + benchmark_cmd.append("--random-range-ratio") + benchmark_cmd.append(str(self.random_range_ratio)) + print_info( + f"Dataset: {dataset_path} is not provided or does not exist. " + f"Use random dataset (random_range_ratio={self.random_range_ratio}) for benchmark." + ) if self.backend: benchmark_cmd.append("--backend") benchmark_cmd.append(self.backend) @@ -424,6 +454,8 @@ def to_cmd(self) -> List[str]: benchmark_cmd.append("--use-chat-template") if not self.streaming: benchmark_cmd.append("--non-streaming") + if self.trust_remote_code: + benchmark_cmd.append("--trust-remote-code") return benchmark_cmd def to_env(self) -> Dict[str, str]: @@ -450,9 +482,11 @@ def to_db_data(self) -> dict: "l_isl": self.isl, "l_osl": self.osl, "d_random_range_ratio": self.random_range_ratio, + "s_dataset_file": self.dataset_file, "s_backend": self.backend, "b_use_chat_template": self.use_chat_template, "b_streaming": self.streaming, + "b_trust_remote_code": self.trust_remote_code, "s_client_log_link": "", "s_client_env_vars": self.env_vars, } @@ -498,6 +532,11 @@ class AggrTestCmds(NamedTuple): client_cmds: Dict[int, List[List[str]]] timeout: int output_dir: str + test_output_dir: str + + def get_server_logs(self, server_idx) -> List[str]: + server_file_path = os.path.join(self.test_output_dir, f"trtllm-serve.{server_idx}.log") + return [server_file_path] def run_cmd(self, server_idx: int) -> List[str]: """Run all clients for a server and return outputs.""" @@ -510,29 +549,28 @@ def run_cmd(self, server_idx: int) -> List[str]: server_port = get_free_port() server_cmd_with_port = add_host_port_to_cmd(server_cmd, server_hostname, server_port) - server_file_path = os.path.join(self.output_dir, f"trtllm-serve.{server_idx}.log") - print_info(f"Starting server. cmd is {server_cmd_with_port}") + server_file_path = os.path.join(self.test_output_dir, f"trtllm-serve.{server_idx}.log") with open(server_file_path, "w") as server_ctx: server_proc = subprocess.Popen( server_cmd_with_port, + env=copy.deepcopy(os.environ), stdout=server_ctx, stderr=subprocess.STDOUT, - env=copy.deepcopy(os.environ), ) - wait_for_endpoint_ready( - f"http://{server_hostname}:{server_port}/health", - timeout=self.timeout, - server_proc=server_proc, - ) + wait_for_endpoint_ready( + f"http://{server_hostname}:{server_port}/health", + timeout=self.timeout, + check_files=[server_file_path], + server_proc=server_proc, + ) # Run all clients for this server for client_idx, client_cmd in enumerate(self.client_cmds[server_idx]): client_file_path = os.path.join( - self.output_dir, f"trtllm-benchmark.{server_idx}.{client_idx}.log" + self.test_output_dir, f"trtllm-benchmark.{server_idx}.{client_idx}.log" ) - client_cmd_with_port = add_host_port_to_cmd( client_cmd, server_hostname, server_port ) @@ -546,7 +584,6 @@ def run_cmd(self, server_idx: int) -> List[str]: with open(client_file_path, "w") as client_ctx: client_ctx.write(output) - outputs.append(output) finally: @@ -571,20 +608,21 @@ class DisaggTestCmds(NamedTuple): num_ctx_servers: int num_gen_servers: int output_dir: str + test_output_dir: str def _generate_hostname_file(self, server_idx: int, port: int): """Create hostname file for coordination.""" - hostnames_dir = os.path.join(self.output_dir, f"hostnames-{server_idx}") + hostnames_dir = os.path.join(self.test_output_dir, f"hostnames-{server_idx}") if not os.path.exists(hostnames_dir): os.makedirs(hostnames_dir, exist_ok=True) hostname_file = os.path.join(hostnames_dir, f"{self.disagg_serving_type}.txt") with open(hostname_file, "w") as f: f.write(f"{self.hostname}:{port}") - def _generate_disagg_server_config(self, server_idx: int, disagg_server_port: int) -> str: + def _generate_disagg_server_config(self, server_idx: int) -> str: """Generate disagg server config from hostname files.""" print_info(f"Generating disagg server config for server index {server_idx}") - hostnames_folder = os.path.join(self.output_dir, f"hostnames-{server_idx}") + hostnames_folder = os.path.join(self.test_output_dir, f"hostnames-{server_idx}") expected_count = self.num_ctx_servers + self.num_gen_servers start_time = time.time() hostnames = [] @@ -597,8 +635,7 @@ def _generate_disagg_server_config(self, server_idx: int, disagg_server_port: in f"expected: {expected_count}" ) if elapsed_time > self.timeout: - print_error(f"Time out. Hostnames files are not ready after {self.timeout}s") - break + raise RuntimeError(f"Time out. Hostnames files are not ready after {self.timeout}s") time.sleep(10) if not os.path.exists(hostnames_folder): continue @@ -620,6 +657,11 @@ def _generate_disagg_server_config(self, server_idx: int, disagg_server_port: in elif hostname_file.startswith("GEN"): gen_hostnames.append(hostname_port) + # Allocate port here (after waiting) to minimize the window between + # port allocation and actual use, avoiding TOCTOU race conditions + # where another process on the same node grabs the port. + disagg_server_port = get_free_port() + server_config = { "hostname": self.hostname, "port": disagg_server_port, @@ -633,7 +675,7 @@ def _generate_disagg_server_config(self, server_idx: int, disagg_server_port: in "urls": gen_hostnames, }, } - config_path = os.path.join(self.output_dir, f"server_config.{server_idx}.yaml") + config_path = os.path.join(self.test_output_dir, f"server_config.{server_idx}.yaml") with open(config_path, "w") as f: yaml.dump(server_config, f) print_info(f"Server config file {config_path} generated") @@ -641,7 +683,7 @@ def _generate_disagg_server_config(self, server_idx: int, disagg_server_port: in def _get_disagg_server_hostname_and_port(self, server_idx: int) -> Tuple[str, int]: """Wait for and read disagg server config.""" - config_path = os.path.join(self.output_dir, f"server_config.{server_idx}.yaml") + config_path = os.path.join(self.test_output_dir, f"server_config.{server_idx}.yaml") start_time = time.time() while True: if os.path.exists(config_path): @@ -649,8 +691,9 @@ def _get_disagg_server_hostname_and_port(self, server_idx: int) -> Tuple[str, in break elapsed_time = time.time() - start_time if elapsed_time > self.timeout: - print_error(f"Server config file {config_path} not found after {self.timeout}s") - break + raise RuntimeError( + f"Server config file {config_path} not found after {self.timeout}s" + ) print_info(f"Waiting for server config file, elapsed time: {elapsed_time}s") time.sleep(10) @@ -670,60 +713,39 @@ def wait_for_benchmark_ready(self, benchmark_status_file: str): elapsed_time = time.time() - start_time print_info(f"Waiting for benchmark status file, elapsed time: {elapsed_time}s") if elapsed_time > self.timeout: - print_error(f"Timeout waiting for benchmark status file after {self.timeout}s") - break - time.sleep(10) - - def wait_for_endpoint_ready(self, url: str, server_files: List[str] = None): - """Wait for endpoint to be ready.""" - start = time.monotonic() - iteration = 0 - error_keywords = ["RuntimeError", "out of memory", "ValueError"] - while True: - iteration += 1 - elapsed_time = time.monotonic() - start - if elapsed_time > self.timeout: - print_error( - f"Timeout waiting for endpoint {url} to be ready after {self.timeout} seconds" + raise RuntimeError( + f"Timeout waiting for benchmark status file after {self.timeout}s" ) - break - print_info(f"Waiting for endpoint {url} to be ready, elapsed time: {elapsed_time}s") - - if server_files and iteration % 30 == 0: - for server_file in server_files: - if os.path.exists(server_file): - try: - with open(server_file, "r") as f: - content = f.read() - for line in content.splitlines(): - for keyword in error_keywords: - if keyword in line: - print_error( - f"Found '{keyword}' in server file {server_file}: {line}" - ) - except Exception as e: - print_info(f"Failed to read server file {server_file}: {e}") + time.sleep(10) - try: - time.sleep(10) - if requests.get(url).status_code == 200: - print_info(f"endpoint {url} is ready") - return - except Exception as err: - print_info(f"endpoint {url} is not ready, with exception: {err}") + def get_server_logs(self, server_idx: int) -> List[str]: + server_logs = [] + for i in range(self.num_ctx_servers): + server_logs.append( + os.path.join(self.test_output_dir, f"trtllm-serve.CTX_{i}.{server_idx}.log") + ) + server_logs.append(os.path.join(self.output_dir, f"ctx_server_{i}.log")) + for i in range(self.num_gen_servers): + server_logs.append( + os.path.join(self.test_output_dir, f"trtllm-serve.GEN_{i}.{server_idx}.log") + ) + server_logs.append(os.path.join(self.output_dir, f"gen_server_{i}.log")) + server_logs.append( + os.path.join(self.test_output_dir, f"trtllm-serve.DISAGG_SERVER.{server_idx}.log") + ) + server_logs.append(os.path.join(self.output_dir, "disagg_server.log")) + return server_logs def run_cmd(self, server_idx: int) -> List[str]: """Run commands for a server and return outputs.""" outputs = [] - benchmark_status_file = os.path.join(self.output_dir, f"benchmark_status.{server_idx}.txt") - port = get_free_port() - + benchmark_status_file = os.path.join( + self.test_output_dir, f"benchmark_status.{server_idx}.txt" + ) ctx_cmd, gen_cmd, disagg_cmd = self.server_cmds[server_idx] if "CTX" in self.disagg_serving_type or "GEN" in self.disagg_serving_type: + port = get_free_port() self._generate_hostname_file(server_idx, port) - server_file_path = os.path.join( - self.output_dir, f"trtllm-serve.{server_idx}.{self.disagg_serving_type}.log" - ) is_ctx = "CTX" in self.disagg_serving_type server_cmd = ctx_cmd if is_ctx else gen_cmd server_cmd = add_host_port_to_cmd(server_cmd, self.hostname, port) @@ -731,34 +753,39 @@ def run_cmd(self, server_idx: int) -> List[str]: print_info( f"Starting server. disagg_serving_type: {self.disagg_serving_type} cmd is {server_cmd}" ) + server_file_path = os.path.join( + self.test_output_dir, + f"trtllm-serve.{self.disagg_serving_type}.{server_idx}.log", + ) with open(server_file_path, "w") as server_ctx: server_proc = subprocess.Popen( server_cmd, + env=copy.deepcopy(os.environ), stdout=server_ctx, stderr=subprocess.STDOUT, - env=copy.deepcopy(os.environ), ) - self.wait_for_benchmark_ready(benchmark_status_file) + self.wait_for_benchmark_ready(benchmark_status_file) finally: print_info(f"Server {self.disagg_serving_type} stopped") server_proc.terminate() server_proc.wait() elif self.disagg_serving_type == "DISAGG_SERVER": - disagg_server_file_path = os.path.join( - self.output_dir, f"trtllm-serve.{server_idx}.{self.disagg_serving_type}.log" - ) try: - self._generate_disagg_server_config(server_idx, port) + self._generate_disagg_server_config(server_idx) print_info(f"Starting disagg server. cmd is {disagg_cmd}") + disagg_server_file_path = os.path.join( + self.test_output_dir, + f"trtllm-serve.{self.disagg_serving_type}.{server_idx}.log", + ) with open(disagg_server_file_path, "w") as disagg_server_ctx: disagg_server_proc = subprocess.Popen( disagg_cmd, + env=copy.deepcopy(os.environ), stdout=disagg_server_ctx, stderr=subprocess.STDOUT, - env=copy.deepcopy(os.environ), ) - self.wait_for_benchmark_ready(benchmark_status_file) + self.wait_for_benchmark_ready(benchmark_status_file) finally: print_info(f"Disagg server {self.disagg_serving_type} stopped") disagg_server_proc.terminate() @@ -769,32 +796,18 @@ def run_cmd(self, server_idx: int) -> List[str]: disagg_server_hostname, disagg_server_port = ( self._get_disagg_server_hostname_and_port(server_idx) ) - server_files = [ - os.path.join(self.output_dir, f"trtllm-serve.{server_idx}.DISAGG_SERVER.log"), - ] - for ctx_idx in range(self.num_ctx_servers): - server_files.append( - os.path.join( - self.output_dir, f"trtllm-serve.{server_idx}.CTX_{ctx_idx}.log" - ) - ) - for gen_idx in range(self.num_gen_servers): - server_files.append( - os.path.join( - self.output_dir, f"trtllm-serve.{server_idx}.GEN_{gen_idx}.log" - ) - ) - self.wait_for_endpoint_ready( + + wait_for_endpoint_ready( f"http://{disagg_server_hostname}:{disagg_server_port}/health", - server_files=server_files, + timeout=self.timeout, + check_files=self.get_server_logs(server_idx), ) # Run all clients for this server for client_idx, client_cmd in enumerate(self.client_cmds[server_idx]): benchmark_file_path = os.path.join( - self.output_dir, f"trtllm-benchmark.{server_idx}.{client_idx}.log" + self.test_output_dir, f"trtllm-benchmark.{server_idx}.{client_idx}.log" ) - client_cmd_with_port = add_host_port_to_cmd( client_cmd, disagg_server_hostname, disagg_server_port ) @@ -833,6 +846,79 @@ def parse_select_pattern(select_pattern: str) -> list: return [name.strip() for name in select_pattern.split(",")] +def parse_test_string(test_case_name: str): + """Parse test case name to get config base name, select pattern, runtime, and benchmark_mode. + + Test name formats: + - Disagg e2e: disagg_upload-e2e-{config_base} + - Disagg gen_only: disagg_upload-gen_only-{config_base} + - ctx_only: aggr_upload-ctx_only-{config_base} (runs aggr mode but reads disagg config) + - Regular aggr: aggr_upload-{config}-{server_name} + + Returns: + tuple: (config_base_name, select_pattern, runtime_mode, benchmark_mode) + - runtime_mode: "aggregated" or "disaggregated" + - benchmark_mode: "e2e", "gen_only", "ctx_only", or None (for normal aggr) + """ + labels = test_case_name.split("-") + + assert len(labels) > 1, "perf_sanity test must have a config file!" + + prefix = labels[0] + is_disagg_prefix = "disagg" in prefix + is_aggr_prefix = "aggr" in prefix + + if is_disagg_prefix: + # Disagg format: disagg_upload-{e2e|gen_only}-{config_base} + assert len(labels) > 2, "Disagg test must have benchmark_mode and config!" + benchmark_mode = labels[1] # e2e or gen_only + assert benchmark_mode in ("e2e", "gen_only"), ( + f"Invalid benchmark_mode for disagg: {benchmark_mode}" + ) + runtime_mode = "disaggregated" + config_base_name = "-".join(labels[2:]) + select_pattern = None + elif is_aggr_prefix: + # Check if this is ctx_only (aggr_upload-ctx_only-{config_base}) + if len(labels) > 2 and labels[1] == "ctx_only": + # ctx_only: aggr_upload-ctx_only-{config_base} + # Runs in aggregated mode but reads disagg config + benchmark_mode = "ctx_only" + runtime_mode = "aggregated" + config_base_name = "-".join(labels[2:]) + select_pattern = None + else: + # Regular aggr: aggr_upload-config_yml or aggr_upload-config_yml-server_config_name + benchmark_mode = None + runtime_mode = "aggregated" + config_base_name = labels[1] + # select_pattern is server config name (e.g., "r1_fp8_dep8_mtp1_1k1k") + select_pattern = "-".join(labels[2:]) if len(labels) > 2 else None + else: + raise ValueError(f"Invalid test name prefix: {prefix}") + + return config_base_name, select_pattern, runtime_mode, benchmark_mode + + +def get_config_dir(benchmark_mode: Optional[str]) -> str: + """Get config directory based on benchmark_mode. + + Args: + benchmark_mode: "e2e", "gen_only", "ctx_only", or None (for normal aggr) + + Returns: + str: Absolute config directory path + """ + if benchmark_mode in ("e2e", "gen_only", "ctx_only"): + config_dir = DISAGG_CONFIG_FOLDER + else: + config_dir = AGG_CONFIG_FOLDER + # If relative path, join with llm root + if not os.path.isabs(config_dir): + config_dir = os.path.join(get_llm_root(), config_dir) + return config_dir + + class PerfSanityTestConfig: """Configuration for perf sanity tests.""" @@ -840,6 +926,10 @@ def __init__(self, test_case_name: str, output_dir: str): self._output_dir = output_dir self._perf_results: Dict[int, List[Dict[str, float]]] = {} + # Initialize server configs + self.server_configs: List = [] + self.server_client_configs: Dict[int, List[ClientConfig]] = {} + # Parse test case name self.parse_test_case_name(test_case_name) @@ -847,68 +937,55 @@ def parse_test_case_name(self, test_case_name: str): """Parse test case name into components.""" self._test_param_labels = test_case_name - # Extract configs from test param labels - labels = self._test_param_labels.split("-") - def get_gpu_type() -> str: try: output = subprocess.check_output( - ["nvidia-smi", "-L"], stderr=subprocess.DEVNULL, text=True + "nvidia-smi -q | grep 'Product Name' | head -1", + shell=True, + stderr=subprocess.DEVNULL, + text=True, ) - first_line = output.strip().split("\n")[0] - gpu_models = SUPPORTED_GPU_TYPE - for model in gpu_models: - if model in first_line: - if model.startswith("B") and not model.startswith("GB"): - return f"dgx_{model.lower()}" - return model.lower() + model = output.split()[-1] + return SUPPORTED_GPU_MAPPING.get(model, "unsupported") except (subprocess.CalledProcessError, FileNotFoundError, IndexError): - print_error("Failed to get GPU type") - return "" + raise RuntimeError("Failed to get GPU type") - assert len(labels) > 1, "perf_sanity test must have a config file!" - is_disagg = "disagg" in labels[0] - self.upload_to_db = "upload" in labels[0] + self.upload_to_db = "upload" in test_case_name.split("-")[0] self.gpu_type = get_gpu_type() - if is_disagg: - # For disagg: disagg_upload-deepseek-r1-fp4_8k1k_ctx1_gen1_dep32_bs128_eplb0_mtp0_ccb-UCX + # Parse test case name to get config_base_name, select_pattern, runtime, benchmark_mode + config_base_name, self.select_pattern, runtime, self.benchmark_mode = parse_test_string( + test_case_name + ) + + # Set runtime based on parsed result + if runtime == "disaggregated": self.runtime = "multi_node_disagg_server" - self.config_dir = "tests/integration/defs/perf/disagg/test_configs/disagg/perf" - config_base = "-".join(labels[1:]) - self.config_file = ( - f"{config_base}.yaml" if not config_base.endswith(".yaml") else config_base - ) - self.select_pattern = None else: - # For aggr: aggr_upload-config_yml or aggr_upload-config_yml-server_config_name self.runtime = "aggr_server" - self.config_dir = "tests/scripts/perf-sanity" - config_base = labels[1] - self.config_file = ( - f"{config_base}.yaml" - if config_base and not config_base.endswith(".yaml") - else config_base - ) - # select_pattern is server config name (e.g., "r1_fp8_dep8_mtp1_1k1k") - self.select_pattern = "-".join(labels[2:]) if len(labels) > 2 else None - self.config_dir = os.getenv( - "TRTLLM_CONFIG_FOLDER", os.path.join(get_llm_root(), self.config_dir) + # Set config_file + self.config_file = ( + f"{config_base_name}.yaml" + if not config_base_name.endswith(".yaml") + else config_base_name ) - # Initialize server configs - self.server_configs: List = [] - self.server_client_configs: Dict[int, List[ClientConfig]] = {} + # Get config_dir based on benchmark_mode + self.config_dir = get_config_dir(self.benchmark_mode) def parse_config_file(self): - """Parse config file based on runtime.""" + """Parse config file based on runtime and benchmark_mode.""" config_file_path = os.path.join(self.config_dir, self.config_file) - if self.runtime == "aggr_server": - self._parse_aggr_config_file(config_file_path) - elif self.runtime == "multi_node_disagg_server": + # benchmark_mode determines which parser to use: + # - e2e, gen_only, ctx_only: use _parse_disagg_config_file (reads disagg config) + # - None (normal aggr): use _parse_aggr_config_file + if self.benchmark_mode in ("e2e", "gen_only", "ctx_only"): self._parse_disagg_config_file(config_file_path, self.config_file) + else: + # Normal aggregated mode + self._parse_aggr_config_file(config_file_path) def _parse_aggr_config_file(self, config_file_path: str): """Parse YAML config file for aggregated server.""" @@ -956,7 +1033,9 @@ def _parse_aggr_config_file(self, config_file_path: str): client_configs = [] for client_config_data in server_config_data["client_configs"]: client_config = ClientConfig( - client_config_data, server_config_data["model_name"], client_env_var + client_config_data, + server_config_data["model_name"], + env_vars=client_env_var, ) client_configs.append(client_config) @@ -966,7 +1045,12 @@ def _parse_aggr_config_file(self, config_file_path: str): self.server_client_configs = server_client_configs def _parse_disagg_config_file(self, config_file_path: str, config_file: str): - """Parse YAML config file for disaggregated server.""" + """Parse YAML config file for disaggregated server. + + This method handles e2e, gen_only, and ctx_only modes. + For ctx_only: output is on par with _parse_aggr_config_file (single ServerConfig), + OSL is set to 1, and cache_transceiver_config is ignored. + """ disagg_serving_type = os.environ.get("DISAGG_SERVING_TYPE", "BENCHMARK") # Get config file base name (without extension) @@ -988,9 +1072,13 @@ def _parse_disagg_config_file(self, config_file_path: str, config_file: str): model_name = metadata.get("model_name", "") assert model_name, "model_name is required in metadata section" - benchmark_mode = benchmark.get("mode", "e2e") - if "gen_only" in benchmark_mode: - hardware["num_ctx_servers"] = 0 + # Use self.benchmark_mode instead of reading from config file + benchmark_mode = self.benchmark_mode + if benchmark_mode == "gen_only": + # Check if it's gen_only_no_context from config + config_mode = benchmark.get("mode", "e2e") + if "gen_only_no_context" in config_mode: + hardware["num_ctx_servers"] = 0 worker_env_var = environment.get("worker_env_var", "") server_env_var = environment.get("server_env_var", "") @@ -1005,90 +1093,120 @@ def _parse_disagg_config_file(self, config_file_path: str, config_file: str): else: concurrency_values = [int(concurrency_str)] - # Gen only mode only runs max concurrency - if "gen_only" in benchmark_mode: - concurrency_values = [max(concurrency_values)] - - # Create ctx server config - ctx_server_config_data = { - "concurrency": max(concurrency_values), - "name": config_file_base_name, - "model_name": model_name, - "gpus_per_node": gpus_per_node, - "disagg_run_type": "ctx", - **worker_config.get("ctx", {}), - } + # Gen only mode only runs the first concurrency + if benchmark_mode == "gen_only": + concurrency_values = [concurrency_values[0]] + + # Handle ctx_only mode specially - output should be on par with _parse_aggr_config_file + if benchmark_mode == "ctx_only": + # Get ctx worker config and modify it + ctx_config = dict(worker_config.get("ctx", {})) + # Ignore cache_transceiver_config for ctx_only + ctx_config.pop("cache_transceiver_config", None) + # Disable overlap scheduler for ctx_only + ctx_config["disable_overlap_scheduler"] = True + + # Create server config for ctx_only (single ServerConfig, not tuple) + ctx_server_config_data = { + "concurrency": -1, # Same as aggr + "name": f"{benchmark_mode}-{config_file_base_name}", + "model_name": model_name, + "gpus_per_node": gpus_per_node, + "disagg_run_type": "aggr", # Run as aggr + **ctx_config, + } - # Create gen server config - gen_server_config_data = { - "concurrency": max(concurrency_values), - "name": config_file_base_name, - "model_name": model_name, - "gpus_per_node": gpus_per_node, - "disagg_run_type": "gen", - **worker_config.get("gen", {}), - } + ctx_server_config = ServerConfig(ctx_server_config_data, worker_env_var) + self.server_configs = [ctx_server_config] + else: + # For e2e and gen_only modes - create ctx and gen server configs + ctx_server_config_data = { + "concurrency": concurrency_values[0], + "name": f"{benchmark_mode}-{config_file_base_name}", + "model_name": model_name, + "gpus_per_node": gpus_per_node, + "disagg_run_type": "ctx", + **worker_config.get("ctx", {}), + } - ctx_server_config = ServerConfig(ctx_server_config_data, worker_env_var) - gen_server_config = ServerConfig(gen_server_config_data, worker_env_var) - - # Create disagg config - disagg_config = DisaggConfig( - name=config_file_base_name, - disagg_serving_type=disagg_serving_type, - hostname=socket.gethostname(), - numa_bind=numa_bind, - timeout=timeout, - benchmark_mode=benchmark_mode, - model_name=model_name, - hardware=hardware, - server_env_var=server_env_var, - ) + gen_server_config_data = { + "concurrency": concurrency_values[0], + "name": f"{benchmark_mode}-{config_file_base_name}", + "model_name": model_name, + "gpus_per_node": gpus_per_node, + "disagg_run_type": "gen", + **worker_config.get("gen", {}), + } - # server_configs is a list with one element (tuple of ctx, gen, disagg config) - self.server_configs = [(ctx_server_config, gen_server_config, disagg_config)] + ctx_server_config = ServerConfig(ctx_server_config_data, worker_env_var) + gen_server_config = ServerConfig(gen_server_config_data, worker_env_var) + + disagg_config = DisaggConfig( + name=f"{benchmark_mode}-{config_file_base_name}", + disagg_serving_type=disagg_serving_type, + hostname=socket.gethostname(), + numa_bind=numa_bind, + timeout=timeout, + benchmark_mode=benchmark_mode, + model_name=model_name, + hardware=hardware, + server_env_var=server_env_var, + ) + + # server_configs is a list with one element (tuple of ctx, gen, disagg config) + self.server_configs = [(ctx_server_config, gen_server_config, disagg_config)] # Create client configs for each concurrency value + # For ctx_only: OSL is set to 1 and dataset_file is empty + osl = 1 if benchmark_mode == "ctx_only" else benchmark.get("output_length", 1024) + dataset_file = "" if benchmark_mode == "ctx_only" else benchmark.get("dataset_file", "") + client_configs = [] for concurrency in concurrency_values: client_config_data = { "concurrency": concurrency, "iterations": benchmark.get("multi_round", 1), "isl": benchmark.get("input_length", 1024), - "osl": benchmark.get("output_length", 1024), + "osl": osl, "random_range_ratio": benchmark.get("benchmark_ratio", 0.0), "backend": "openai", "use_chat_template": False, "streaming": benchmark.get("streaming", True), + "dataset_file": dataset_file, } - client_config = ClientConfig(client_config_data, model_name, client_env_var) + client_config = ClientConfig( + client_config_data, + model_name, + env_vars=client_env_var, + ) client_configs.append(client_config) self.server_client_configs = {0: client_configs} def get_commands(self): - """Get commands based on runtime.""" - perf_sanity_output_dir = os.path.join(self._output_dir, self._test_param_labels) - os.makedirs(perf_sanity_output_dir, exist_ok=True) + """Get commands based on runtime and benchmark_mode.""" + self.test_output_dir = os.path.join(self._output_dir, self._test_param_labels) + os.makedirs(self.test_output_dir, exist_ok=True) + # ctx_only runs in aggregated mode (uses _get_aggr_commands) if self.runtime == "aggr_server": - return self._get_aggr_commands(perf_sanity_output_dir) - elif self.runtime == "multi_node_disagg_server": - return self._get_disagg_commands(perf_sanity_output_dir) + return self._get_aggr_commands(self._output_dir, self.test_output_dir) + else: + return self._get_disagg_commands(self._output_dir, self.test_output_dir) - def _get_aggr_commands(self, output_dir: str): + def _get_aggr_commands(self, output_dir: str, test_output_dir: str): """Get commands for aggregated server.""" server_cmds = [] client_cmds = {} for server_idx, client_configs in self.server_client_configs.items(): server_config = self.server_configs[server_idx] - server_cmd = server_config.to_cmd(output_dir) + server_cmd = server_config.to_cmd(test_output_dir) # Generate extra-llm-api-config.yml config_content = server_config.generate_extra_llm_api_config() config_filename = f"extra-llm-api-config.aggr.{server_config.name}.yml" - config_path = os.path.join(output_dir, config_filename) + config_path = os.path.join(test_output_dir, config_filename) with open(config_path, "w") as f: f.write(config_content) @@ -1104,9 +1222,10 @@ def _get_aggr_commands(self, output_dir: str): client_cmds=client_cmds, timeout=DEFAULT_TIMEOUT, output_dir=output_dir, + test_output_dir=test_output_dir, ) - def _get_disagg_commands(self, output_dir: str): + def _get_disagg_commands(self, output_dir: str, test_output_dir: str): """Get commands for disaggregated server.""" server_cmds = [] client_cmds = {} @@ -1117,21 +1236,21 @@ def _get_disagg_commands(self, output_dir: str): disagg_serving_type = disagg_config.disagg_serving_type # Generate ctx server command - ctx_cmd = ctx_config.to_cmd(output_dir, numa_bind, "CTX") + ctx_cmd = ctx_config.to_cmd(test_output_dir, numa_bind, "CTX") if "CTX" in disagg_serving_type: config_content = ctx_config.generate_extra_llm_api_config() config_path = os.path.join( - output_dir, f"extra-llm-api-config.ctx.{ctx_config.name}.yml" + test_output_dir, f"extra-llm-api-config.ctx.{ctx_config.name}.yml" ) with open(config_path, "w") as f: f.write(config_content) # Generate gen server command - gen_cmd = gen_config.to_cmd(output_dir, numa_bind, "GEN") + gen_cmd = gen_config.to_cmd(test_output_dir, numa_bind, "GEN") if "GEN" in disagg_serving_type: config_content = gen_config.generate_extra_llm_api_config() config_path = os.path.join( - output_dir, f"extra-llm-api-config.gen.{gen_config.name}.yml" + test_output_dir, f"extra-llm-api-config.gen.{gen_config.name}.yml" ) with open(config_path, "w") as f: f.write(config_content) @@ -1141,7 +1260,7 @@ def _get_disagg_commands(self, output_dir: str): "trtllm-serve", "disaggregated", "-c", - f"{output_dir}/server_config.{server_idx}.yaml", + f"{test_output_dir}/server_config.{server_idx}.yaml", "-t", str(timeout), "-r", @@ -1166,40 +1285,10 @@ def _get_disagg_commands(self, output_dir: str): num_ctx_servers=disagg_config.num_ctx_servers, num_gen_servers=disagg_config.num_gen_servers, output_dir=output_dir, + test_output_dir=test_output_dir, ) - def run_ex(self, commands) -> Dict[int, List[str]]: - """Run commands and collect outputs.""" - outputs = {} - - for server_idx in range(len(commands.server_cmds)): - try: - with io.StringIO() as buf: - with contextlib.redirect_stdout(buf): - server_outputs = commands.run_cmd(server_idx) - for output in server_outputs: - print(collect_and_clean_myelin_time(output)) - - # Check for errors in each output - for output in server_outputs: - self._check_benchmark_output_for_errors(output) - - print(buf.getvalue()) - - outputs[server_idx] = server_outputs - - except Exception as e: - print_error(f"Test command failed for server {server_idx}. Error: {e}") - if isinstance(e, subprocess.CalledProcessError): - print_error("--- stdout ---") - if e.stdout: - print_error(e.stdout.decode() if isinstance(e.stdout, bytes) else e.stdout) - print_error("--------------") - outputs[server_idx] = [] - - return outputs - - def _check_benchmark_output_for_errors(self, output: str) -> None: + def _check_benchmark_errors(self, output: str) -> None: """Check whether the benchmark output contains error messages.""" if not output: return @@ -1210,12 +1299,31 @@ def _check_benchmark_output_for_errors(self, output: str) -> None: failed_count = int(failed_requests_match.group(1)) if failed_count > 0: error_msg = f"Benchmark output contains {failed_count} failed requests." - raise Exception(error_msg) + raise RuntimeError(error_msg) # Check for explicit failure markers if "!FAILED REQUESTS!" in output or "!CHECK LOG FOR ERRORS!" in output: error_msg = "Benchmark output contains failure markers." - raise Exception(error_msg) + raise RuntimeError(error_msg) + + def run_ex(self, commands) -> Dict[int, List[str]]: + """Run commands and collect outputs.""" + outputs = {} + for server_idx in range(len(commands.server_cmds)): + try: + server_outputs = commands.run_cmd(server_idx) + for output in server_outputs: + self._check_benchmark_errors(output) + outputs[server_idx] = server_outputs + + except Exception as e: + outputs[server_idx] = [] + report_error( + error_msg=e, + log_files=commands.get_server_logs(server_idx), + ) + + return outputs def get_perf_result(self, outputs: Dict[int, List[str]]): """Parse performance results from outputs.""" @@ -1257,12 +1365,9 @@ def check_test_failure(self): f"Some metrics in Server {server_idx} Client {client_idx} are missing. " f"The broken metrics is {metrics}. " ) - if error_msg: raise Exception(error_msg) - print_info("All servers passed") - def upload_test_results_to_database(self): """Upload test results and baseline to database.""" @@ -1327,7 +1432,7 @@ def add_dict_prefix(config_dict: dict, prefix_name: str) -> dict: if not match_keys: if server_config.match_mode == "scenario": match_keys = SCENARIO_MATCH_FIELDS.copy() - is_scenario_mode = True + is_scenario_mode = True # noqa: F841 else: match_keys.extend(["s_gpu_type", "s_runtime"]) match_keys.extend(server_config.to_match_keys()) @@ -1440,16 +1545,18 @@ def add_dict_prefix(config_dict: dict, prefix_name: str) -> dict: # Upload the new perf data and baseline data to database post_new_perf_data(new_baseline_data_dict, new_data_dict) - check_perf_regression(new_data_dict, fail_on_regression=is_scenario_mode) + generate_perf_yaml( + new_data_dict, + output_dir=self.test_output_dir, + ) + # TODO: Re-enable regression failure check if needed + # check_perf_regression(new_data_dict, fail_on_regression=is_scenario_mode, output_dir=self.test_output_dir) # Perf sanity test case parameters AGG_TEST_TYPES = ["aggr_upload", "aggr"] DISAGG_TEST_TYPES = ["disagg_upload", "disagg"] -AGGR_CONFIG_FOLDER = "tests/scripts/perf-sanity" -DISAGG_CONFIG_FOLDER = "tests/integration/defs/perf/disagg/test_configs/disagg/perf" - def get_server_config_names(yaml_path: str) -> List[str]: """Read a YAML file and return the list of server_config names.""" @@ -1476,8 +1583,10 @@ def get_yaml_files_with_server_names(directory: str) -> Dict[str, List[str]]: def get_aggr_test_cases() -> List[str]: """Generate aggr test cases based on actual server_config names in YAML files.""" - llm_root = get_llm_root() - aggr_config_dir = os.path.join(llm_root, AGGR_CONFIG_FOLDER) + aggr_config_dir = AGG_CONFIG_FOLDER + # If relative path, join with llm root + if not os.path.isabs(aggr_config_dir): + aggr_config_dir = os.path.join(get_llm_root(), aggr_config_dir) yaml_server_names = get_yaml_files_with_server_names(aggr_config_dir) test_cases = [] @@ -1494,16 +1603,24 @@ def get_aggr_test_cases() -> List[str]: def get_disagg_test_cases() -> List[str]: - """Generate disagg test cases.""" - llm_root = get_llm_root() - disagg_config_dir = os.path.join(llm_root, DISAGG_CONFIG_FOLDER) + """Generate disagg test cases with benchmark modes.""" + disagg_config_dir = DISAGG_CONFIG_FOLDER + # If relative path, join with llm root + if not os.path.isabs(disagg_config_dir): + disagg_config_dir = os.path.join(get_llm_root(), disagg_config_dir) yaml_files = glob.glob(os.path.join(disagg_config_dir, "*.yaml")) basenames = sorted([os.path.splitext(os.path.basename(f))[0] for f in yaml_files]) test_cases = [] for config_yml in basenames: + # Disagg e2e and gen_only test cases for test_type in DISAGG_TEST_TYPES: - test_cases.append(f"{test_type}-{config_yml}") + test_cases.append(f"{test_type}-e2e-{config_yml}") + test_cases.append(f"{test_type}-gen_only-{config_yml}") + + # ctx_only test cases (uses aggr prefix) + for test_type in AGG_TEST_TYPES: + test_cases.append(f"{test_type}-ctx_only-{config_yml}") return test_cases diff --git a/tests/scripts/perf-sanity/README.md b/tests/scripts/perf-sanity/README.md index 1fcd31d84c6b..6dc64b03680c 100644 --- a/tests/scripts/perf-sanity/README.md +++ b/tests/scripts/perf-sanity/README.md @@ -2,6 +2,8 @@ Performance sanity testing scripts for TensorRT-LLM with configuration-driven test cases supporting single-node, multi-node aggregated, and multi-node disaggregated architectures. +This document serves as a reference for both developers and AI agents working with the perf sanity system. + ## Overview - Run performance sanity benchmarks across multiple model configs @@ -9,17 +11,53 @@ Performance sanity testing scripts for TensorRT-LLM with configuration-driven te - Manage test cases through YAML config files - Automated resource calculation and job submission via SLURM -## Configuration File Types +## System Architecture + +### Key Scripts + +| Script | Purpose | SLURM Launch Draft | +|--------|---------|-------------------| +| `tests/integration/defs/perf/test_perf_sanity.py` | Main pytest entry point for all perf sanity tests | N/A | +| `jenkins/scripts/perf/disaggregated/submit.py` | CI submission script (disaggregated tests only) | Uses `jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh` | +| `jenkins/scripts/perf/local/submit.py` | Local submission script (both aggregated and disaggregated tests) | Uses `jenkins/scripts/perf/aggregated/slurm_launch_draft.sh` or `jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh` | +| `jenkins/L0_Test.groovy` | Jenkins CI pipeline for test orchestration | N/A | + +### SLURM Launch Script Generation + +The submit scripts generate `slurm_launch.sh` from draft templates: + +| Submit Script | Mode | Draft Template Used | +|---------------|------|---------------------| +| `jenkins/scripts/perf/disaggregated/submit.py` | Disaggregated (CI only) | `jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh` | +| `jenkins/scripts/perf/local/submit.py` | Aggregated (local) | `jenkins/scripts/perf/aggregated/slurm_launch_draft.sh` | +| `jenkins/scripts/perf/local/submit.py` | Disaggregated (local) | `jenkins/scripts/perf/disaggregated/slurm_launch_draft.sh` | + +## Environment Variables + +The config folder paths can be overridden via environment variables. Both submit scripts (`local/submit.py` and `disaggregated/submit.py`) propagate these into the pytest execution environment. + +| Variable | Default | Description | +|----------|---------|-------------| +| `AGG_CONFIG_FOLDER` | `tests/scripts/perf-sanity/aggregated` | Path to aggregated config YAML files | +| `DISAGG_CONFIG_FOLDER` | `tests/scripts/perf-sanity/disaggregated` | Path to disaggregated config YAML files | + +**Example**: Run with custom config folders: +```bash +AGG_CONFIG_FOLDER=my/custom/agg DISAGG_CONFIG_FOLDER=my/custom/disagg \ + python jenkins/scripts/perf/local/submit.py ... +``` + +## Configuration Files There are two modes for perf sanity tests: aggregated (aggr) and disaggregated (disagg). -### Aggregated Mode (aggr) +### Aggregated Mode Config Files -**Config Location**: [`tests/scripts/perf-sanity`](./) +**Location**: `tests/scripts/perf-sanity/aggregated` **File Naming**: `xxx.yaml` where words are connected by `_` (underscore), not `-` (hyphen). -**File Examples**: +**Examples**: - `deepseek_r1_fp4_v2_grace_blackwell.yaml` - Single-node aggregated test - `deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml` - Multi-node aggregated test @@ -27,53 +65,171 @@ There are two modes for perf sanity tests: aggregated (aggr) and disaggregated ( - Single-node: Performance tests on a single server with multiple GPUs - Multi-node: Model runs across multiple nodes with unified execution -**Test Case Names**: +### Disaggregated Mode Config Files + +**Location**: `tests/scripts/perf-sanity/disaggregated` + +**File Naming**: `xxx.yaml` (can contain `-` hyphen). + +**Example**: `deepseek-r1-fp4_1k1k_ctx1_gen1_dep8_bs768_eplb0_mtp0_ccb-UCX.yaml` + +**Use Case**: Disaggregated architecture where model runs across multiple nodes with separate context (prefill) and generation (decode) servers. + +## Test Case Formats + +In each test db yml file (with keyword `perf_sanity`), there are four test types: + +### 1. Normal Aggregated Test + +Uses aggregated config files from `tests/scripts/perf-sanity/aggregated`. + +**Format**: ``` -perf/test_perf_sanity.py::test_e2e[aggr_upload-{config yaml file base name}] -perf/test_perf_sanity.py::test_e2e[aggr_upload-{config yaml file base name}-{server_config_name}] +perf/test_perf_sanity.py::test_e2e[aggr_upload-{agg config file base name}-{test name}] ``` -- Without server config name: runs all server configs in the YAML file -- With server config name: runs only the specified server config (the `name` field in `server_configs`) - -**Examples**: +**Example**: ``` -perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell] perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell-r1_fp4_v2_dep4_mtp1_1k1k] -perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell-r1_fp4_v2_tep4_mtp3_1k1k] ``` -### Disaggregated Mode (disagg) +### 2. Aggregated ctx_only Test -**Config Location**: [`tests/integration/defs/perf/disagg/test_configs/disagg/perf`](../../integration/defs/perf/disagg/test_configs/disagg/perf) +Uses disaggregated config files but runs context (prefill) phase only in aggregated mode. -**File Naming**: `xxx.yaml` (can contain `-` hyphen). +**Format**: +``` +perf/test_perf_sanity.py::test_e2e[aggr_upload-ctx_only-{disagg config file base name}] +``` -**File Example**: `deepseek-r1-fp4_1k1k_ctx1_gen1_dep8_bs768_eplb0_mtp0_ccb-UCX.yaml` +**Example**: +``` +perf/test_perf_sanity.py::test_e2e[aggr_upload-ctx_only-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8] +``` -**Use Case**: Disaggregated architecture where model runs across multiple nodes with separate context (prefill) and generation (decode) servers. +### 3. Disaggregated gen_only Test + +Uses disaggregated config files and runs generation (decode) phase only. -**Test Case Name**: +**Format**: ``` -perf/test_perf_sanity.py::test_e2e[disagg_upload-{config yaml file base name}] +perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-{disagg config file base name}] ``` **Example**: ``` -perf/test_perf_sanity.py::test_e2e[disagg_upload-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8_bs768_eplb0_mtp0_ccb-UCX] +perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8] ``` +### 4. Disaggregated e2e Test + +Uses disaggregated config files and runs full end-to-end disaggregated flow. + +**Format**: +``` +perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-{disagg config file base name}] +``` + +**Example**: +``` +perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8] +``` + +## CI Test Database + +Test lists are defined in `tests/integration/test_lists/test-db/`. + +### YAML File Naming Convention + +| Test Type | File Pattern | Example | +|-----------|--------------|---------| +| Single-node aggregated | `l0_{gpu_type}_multi_gpus_perf_sanity.yml` | `l0_b200_multi_gpus_perf_sanity.yml` | +| Multi-node aggregated | `l0_{gpu_type}_multi_nodes_perf_sanity_node{node count}_gpu{gpu count per test}.yml` | `l0_b200_multi_nodes_perf_sanity_node2_gpu16.yml` | +| Multi-node disaggregated | `l0_{gpu_type}_multi_gpus_perf_sanity_ctx{ctx worker count}node{node count per ctx worker}_gpu{gpu count per ctx worker}_gen{gen worker count}node{node count per gen worker}_gpu{gen gpus per gen worker}.yml` | `l0_b200_multi_gpus_perf_sanity_ctx1node1_gpu8_gen1node1_gpu8.yml` | + +### Jenkins Pipeline Configuration + +Tests are defined in `jenkins/L0_Test.groovy` under the `launchTestJobs` function: + +| Config Variable | Test Type | +|-----------------|-----------| +| `x86SlurmTestConfigs` | Single-node aggregated tests | +| `SBSASlurmTestConfigs` | Multi-node aggregated tests | +| `multiNodesSBSAConfigs` | Multi-node disaggregated tests | + +## CI Stage Rules + +### Test Batching Rules + +| Test Type | Nodes per Test | Max Tests per Stage | Notes | +|-----------|----------------|---------------------|-------| +| Normal aggregated test | 1 | 6 | Multiple tests can share a stage | +| Aggregated ctx_only test | 1 | 6 | Multiple tests can share a stage | +| Normal aggregated test | > 1 | 1 | One test per stage | +| Aggregated ctx_only test | > 1 | 1 | One test per stage | +| Disaggregated gen_only test | Any | 1 | Always one test per stage | +| Disaggregated e2e test | Any | 1 | Always one test per stage | + +**Important**: Pre-merge and post-merge tests must be in separate stages. + +### GPU Hours Calculation + +- Each CI stage runtime is approximately **1 hour** +- GPU hours = (number of stages) x (GPUs per stage) x 1 hour + +**Example**: A test configuration with 12 single-node tests (6 tests x 2 stages) using 8 GPUs each = 2 stages x 8 GPUs x 1 hour = 16 GPU hours + ## Running Tests **Important**: Do NOT add `--perf` flag when running pytest. Perf sanity tests are static test cases and do not use perf mode. -```bash -# Run all server configs in an aggregated test -pytest perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell] +### Local Run Examples -# Run a specific server config in an aggregated test +```bash +# Run a normal aggregated test pytest perf/test_perf_sanity.py::test_e2e[aggr_upload-deepseek_r1_fp4_v2_grace_blackwell-r1_fp4_v2_dep4_mtp1_1k1k] -# Run a specific disaggregated test -pytest perf/test_perf_sanity.py::test_e2e[disagg_upload-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8_bs768_eplb0_mtp0_ccb-UCX] +# Run an aggregated ctx_only test +pytest perf/test_perf_sanity.py::test_e2e[aggr_upload-ctx_only-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8] + +# Run a disaggregated gen_only test +pytest perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8] + +# Run a disaggregated e2e test +pytest perf/test_perf_sanity.py::test_e2e[disagg_upload-e2e-deepseek-r1-fp4_1k1k_ctx1_gen1_dep8] +``` + +### Using Local Submit Script + +For local SLURM job submission (supports both aggregated and disaggregated tests): + +```bash +python jenkins/scripts/perf/local/submit.py --help ``` + +## Disaggregated Test SLURM Execution + +A disaggregated test runs **four srun steps** within a single multi-node SLURM job allocation. Each step has a different role set via `DISAGG_SERVING_TYPE`: + +| Step | `DISAGG_SERVING_TYPE` | Needs MPI | Notes | +|------|-----------------------|-----------|-------| +| Context worker(s) | `CTX_0`, `CTX_1`, ... | Yes | Launched via `trtllm-llmapi-launch`, multi-GPU | +| Generation worker(s) | `GEN_0`, `GEN_1`, ... | Yes | Launched via `trtllm-llmapi-launch`, multi-GPU | +| Disagg server | `DISAGG_SERVER` | No | Runs `trtllm-serve disaggregated`, single process | +| Benchmark client | `BENCHMARK` | No | Runs benchmark pytest, single process | + +All four srun steps share the same `srunArgs` array, but `--mpi=pmix` is added **only** to the CTX/GEN worker srun commands in `slurm_launch_draft.sh` (not in srunArgs). This prevents unwanted MPI initialization in the disagg server and benchmark processes. See the MPI/PMI section in `jenkins/scripts/perf/README.md` for details. + +## Quick Reference for AI Agents + +When working with perf sanity tests, use these paths: + +| Resource | Path | +|----------|------| +| Pytest script | `tests/integration/defs/perf/test_perf_sanity.py` | +| Aggregated configs | `tests/scripts/perf-sanity/aggregated/*.yaml` | +| Disaggregated configs | `tests/scripts/perf-sanity/disaggregated/*.yaml` | +| CI submit (disagg only) | `jenkins/scripts/perf/disaggregated/submit.py` | +| Local submit (all) | `jenkins/scripts/perf/local/submit.py` | +| Jenkins pipeline | `jenkins/L0_Test.groovy` | +| Test database | `tests/integration/test_lists/test-db/` | diff --git a/tests/scripts/perf-sanity/config_database_b200_nvl.yaml b/tests/scripts/perf-sanity/aggregated/config_database_b200_nvl.yaml similarity index 59% rename from tests/scripts/perf-sanity/config_database_b200_nvl.yaml rename to tests/scripts/perf-sanity/aggregated/config_database_b200_nvl.yaml index b579f03170c9..2a3e8b3549ee 100644 --- a/tests/scripts/perf-sanity/config_database_b200_nvl.yaml +++ b/tests/scripts/perf-sanity/aggregated/config_database_b200_nvl.yaml @@ -1,12 +1,12 @@ server_configs: -- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc4_gpu4 - model_name: deepseek_r1_0528_fp4_v2 - gpus: 4 +- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc1_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 1 print_iter_log: true kv_cache_config: dtype: fp8 @@ -15,29 +15,31 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 + max_num_tokens: 3136 max_seq_len: 2068 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1_isl1024_osl1024 + concurrency: 1 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc32_gpu4 - model_name: deepseek_r1_0528_fp4_v2 - gpus: 4 +- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc32_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 32 print_iter_log: true kv_cache_config: dtype: fp8 @@ -46,11 +48,13 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 + max_num_tokens: 3136 max_seq_len: 2068 client_configs: - name: con32_isl1024_osl1024 @@ -61,10 +65,11 @@ server_configs: random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc256_gpu4 - model_name: deepseek_r1_0528_fp4_v2 - gpus: 4 +- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc2048_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true max_batch_size: 512 @@ -76,34 +81,36 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: CUTLASS + backend: DEEPGEMM attention_dp_config: batching_wait_iters: 0 enable_balance: true timeout_iters: 60 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1344 + max_num_tokens: 2112 max_seq_len: 2068 client_configs: - - name: con256_isl1024_osl1024 - concurrency: 256 + - name: con2048_isl1024_osl1024 + concurrency: 2048 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc4_gpu8 - model_name: deepseek_r1_0528_fp4_v2 +- name: deepseek_ai_DeepSeek_R1_0528_1024_8192_conc1_gpu8 + model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 1 print_iter_log: true kv_cache_config: dtype: fp8 @@ -112,29 +119,31 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 - max_seq_len: 2068 + max_num_tokens: 3136 + max_seq_len: 9416 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1_isl1024_osl8192 + concurrency: 1 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc32_gpu8 - model_name: deepseek_r1_0528_fp4_v2 +- name: deepseek_ai_DeepSeek_R1_0528_1024_8192_conc32_gpu8 + model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 32 print_iter_log: true kv_cache_config: dtype: fp8 @@ -143,28 +152,30 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 - max_seq_len: 2068 + max_seq_len: 9416 client_configs: - - name: con32_isl1024_osl1024 + - name: con32_isl1024_osl8192 concurrency: 32 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc256_gpu8 - model_name: deepseek_r1_0528_fp4_v2 +- name: deepseek_ai_DeepSeek_R1_0528_1024_8192_conc2048_gpu8 + model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 512 + max_batch_size: 256 enable_attention_dp: true print_iter_log: true kv_cache_config: @@ -173,34 +184,36 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: CUTLASS + backend: DEEPGEMM attention_dp_config: batching_wait_iters: 0 enable_balance: true timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1344 - max_seq_len: 2068 + max_num_tokens: 3072 + max_seq_len: 9416 client_configs: - - name: con256_isl1024_osl1024 - concurrency: 256 + - name: con2048_isl1024_osl8192 + concurrency: 2048 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc4_gpu4 - model_name: deepseek_r1_0528_fp4_v2 - gpus: 4 +- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc1_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 1 print_iter_log: true kv_cache_config: dtype: fp8 @@ -209,42 +222,51 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 10304 max_seq_len: 9416 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con1_isl8192_osl1024 + concurrency: 1 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc32_gpu4 - model_name: deepseek_r1_0528_fp4_v2 - gpus: 4 +- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc32_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 32 + enable_attention_dp: true print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.8 + free_gpu_memory_fraction: 0.7 enable_block_reuse: false stream_interval: 10 moe_config: - backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + backend: DEEPGEMM + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 100 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 9280 max_seq_len: 9416 client_configs: - name: con32_isl8192_osl1024 @@ -255,10 +277,11 @@ server_configs: random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc256_gpu4 - model_name: deepseek_r1_0528_fp4_v2 - gpus: 4 +- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc2048_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true max_batch_size: 512 @@ -266,38 +289,40 @@ server_configs: print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.8 + free_gpu_memory_fraction: 0.7 enable_block_reuse: false stream_interval: 10 moe_config: - backend: CUTLASS + backend: DEEPGEMM attention_dp_config: batching_wait_iters: 0 enable_balance: true - timeout_iters: 60 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + timeout_iters: 100 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8512 + max_num_tokens: 9280 max_seq_len: 9416 client_configs: - - name: con256_isl8192_osl1024 - concurrency: 256 + - name: con2048_isl8192_osl1024 + concurrency: 2048 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc4_gpu8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc1_gpu8 model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 1 print_iter_log: true kv_cache_config: dtype: fp8 @@ -306,29 +331,30 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 - max_seq_len: 9416 + max_seq_len: 2068 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con1_isl1024_osl1024 + concurrency: 1 iterations: 10 - isl: 8192 + isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc32_gpu8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc32_gpu8 model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 512 - enable_attention_dp: false + max_batch_size: 32 print_iter_log: true kv_cache_config: dtype: fp8 @@ -337,25 +363,28 @@ server_configs: stream_interval: 10 moe_config: backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 - max_seq_len: 9416 + max_num_tokens: 3136 + max_seq_len: 2068 client_configs: - - name: con32_isl8192_osl1024 + - name: con32_isl1024_osl1024 concurrency: 32 iterations: 10 - isl: 8192 + isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc256_gpu8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_1024_conc2048_gpu8 model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true max_batch_size: 512 @@ -375,26 +404,24 @@ server_configs: tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8512 - max_seq_len: 9416 + max_seq_len: 2068 client_configs: - - name: con256_isl8192_osl1024 - concurrency: 256 + - name: con2048_isl1024_osl1024 + concurrency: 2048 iterations: 10 - isl: 8192 + isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc4_gpu8 - model_name: deepseek_r1_0528_fp8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_8192_conc1_gpu8 + model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 1024 cuda_graph_config: enable_padding: true - max_batch_size: 256 - enable_attention_dp: false + max_batch_size: 1024 print_iter_log: true kv_cache_config: dtype: fp8 @@ -402,30 +429,32 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: DEEPGEMM + backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 - max_seq_len: 2068 + max_num_tokens: 5248 + max_seq_len: 9416 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1_isl1024_osl8192 + concurrency: 1 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc16_gpu8 - model_name: deepseek_r1_0528_fp8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_8192_conc32_gpu8 + model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 1024 cuda_graph_config: enable_padding: true - max_batch_size: 256 - enable_attention_dp: false + max_batch_size: 1024 print_iter_log: true kv_cache_config: dtype: fp8 @@ -433,30 +462,33 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: DEEPGEMM + backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 - max_seq_len: 2068 + max_num_tokens: 5248 + max_seq_len: 9416 client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 + - name: con32_isl1024_osl8192 + concurrency: 32 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc64_gpu8 - model_name: deepseek_r1_0528_fp8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_8192_conc1024_gpu8 + model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 256 cuda_graph_config: enable_padding: true max_batch_size: 256 - enable_attention_dp: false + enable_attention_dp: true print_iter_log: true kv_cache_config: dtype: fp8 @@ -464,30 +496,36 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: DEEPGEMM + backend: CUTLASS + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 - max_seq_len: 2068 + max_seq_len: 9416 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con1024_isl1024_osl8192 + concurrency: 1024 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc4_gpu8 - model_name: deepseek_r1_0528_fp8 - gpus: 8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_1024_8192_conc2048_gpu4 + model_name: deepseek_r1_0528_fp4_v2 + gpus: 4 match_mode: scenario + max_batch_size: 256 cuda_graph_config: enable_padding: true max_batch_size: 256 - enable_attention_dp: false + enable_attention_dp: true print_iter_log: true kv_cache_config: dtype: fp8 @@ -495,30 +533,68 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: DEEPGEMM + backend: CUTLASS + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + trust_remote_code: true + max_seq_len: 9416 + client_configs: + - name: con2048_isl1024_osl8192 + concurrency: 2048 + iterations: 10 + isl: 1024 + osl: 8192 + random_range_ratio: 0.0 + backend: openai + streaming: true +- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc1_gpu8 + model_name: deepseek_r1_0528_fp4_v2 + gpus: 8 + match_mode: scenario + max_batch_size: 512 + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + print_iter_log: true + kv_cache_config: + dtype: fp8 + free_gpu_memory_fraction: 0.8 + enable_block_reuse: false + stream_interval: 10 + moe_config: + backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 10304 max_seq_len: 9416 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con1_isl8192_osl1024 + concurrency: 1 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc16_gpu8 - model_name: deepseek_r1_0528_fp8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc16_gpu8 + model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 256 - enable_attention_dp: false + max_batch_size: 16 print_iter_log: true kv_cache_config: dtype: fp8 @@ -526,12 +602,14 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: DEEPGEMM + backend: TRTLLM + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 10304 max_seq_len: 9416 client_configs: - name: con16_isl8192_osl1024 @@ -542,13 +620,12 @@ server_configs: random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc64_gpu8 - model_name: deepseek_r1_0528_fp8 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc512_gpu8 + model_name: deepseek_r1_0528_fp4_v2 gpus: 8 match_mode: scenario cuda_graph_config: enable_padding: true - max_batch_size: 256 enable_attention_dp: true print_iter_log: true kv_cache_config: @@ -557,1217 +634,753 @@ server_configs: enable_block_reuse: false stream_interval: 10 moe_config: - backend: DEEPGEMM + backend: TRTLLM attention_dp_config: batching_wait_iters: 0 enable_balance: true timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 8768 max_seq_len: 9416 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con512_isl8192_osl1024 + concurrency: 512 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc1024_gpu4 + model_name: deepseek_r1_0528_fp4_v2 + gpus: 4 match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 256 + enable_attention_dp: true + print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.85 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 + stream_interval: 10 moe_config: - backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + backend: CUTLASS + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 + max_num_tokens: 8768 + max_seq_len: 9416 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1024_isl8192_osl1024 + concurrency: 1024 iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 +- name: nvidia_DeepSeek_R1_0528_FP4_v2_8192_1024_conc2048_gpu4 + model_name: deepseek_r1_0528_fp4_v2 + gpus: 4 match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 256 + enable_attention_dp: true + print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.85 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 + stream_interval: 10 moe_config: - backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + backend: CUTLASS + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 + max_num_tokens: 8768 + max_seq_len: 9416 client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con2048_isl8192_osl1024 + concurrency: 2048 iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 - iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu8 +- name: openai_gpt_oss_120b_1024_1024_conc1_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 1 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false + max_batch_size: 1 print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 - client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 num_postprocess_workers: 4 - moe_config: - backend: TRTLLM tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con1_isl1024_osl1024 + concurrency: 1 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu1 +- name: openai_gpt_oss_120b_1024_1024_conc384_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 1 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - NCCL_GRAPH_REGISTER: 0 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: fp8 - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - print_iter_log: true - stream_interval: 20 - num_postprocess_workers: 4 - moe_config: - backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 384 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 384 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + num_postprocess_workers: 4 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 9236 + max_seq_len: 2068 client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 + - name: con384_isl1024_osl1024 + concurrency: 384 iterations: 10 isl: 1024 - osl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu2 +- name: openai_gpt_oss_120b_1024_1024_conc2048_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 256 + enable_attention_dp: true + print_iter_log: true kv_cache_config: - dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: - backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + backend: CUTLASS + attention_dp_config: + enable_balance: true + num_postprocess_workers: 4 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 9236 + max_seq_len: 2068 client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 + - name: con2048_isl1024_osl1024 + concurrency: 2048 iterations: 10 isl: 1024 - osl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu4 +- name: openai_gpt_oss_120b_1024_1024_conc8_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 8 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 8 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 9236 + max_seq_len: 2068 client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 + - name: con8_isl1024_osl1024 + concurrency: 8 iterations: 10 isl: 1024 - osl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu4 +- name: openai_gpt_oss_120b_1024_1024_conc256_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 256 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 9236 + max_seq_len: 2068 client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 + - name: con256_isl1024_osl1024 + concurrency: 256 iterations: 10 isl: 1024 - osl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu4 +- name: openai_gpt_oss_120b_1024_1024_conc1536_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 1536 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 1536 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 9236 + max_seq_len: 2068 client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 + - name: con1536_isl1024_osl1024 + concurrency: 1536 iterations: 10 isl: 1024 - osl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu8 +- name: openai_gpt_oss_120b_1024_8192_conc1_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 1 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 1 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 + - name: con1_isl1024_osl8192 + concurrency: 1 iterations: 10 isl: 1024 osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu8 +- name: openai_gpt_oss_120b_1024_8192_conc32_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 32 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 32 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 + - name: con32_isl1024_osl8192 + concurrency: 32 iterations: 10 isl: 1024 osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu8 +- name: openai_gpt_oss_120b_1024_8192_conc2048_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 256 + enable_attention_dp: true + print_iter_log: true kv_cache_config: - dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: - backend: TRTLLM + backend: CUTLASS + attention_dp_config: + enable_balance: true + num_postprocess_workers: 4 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 + - name: con2048_isl1024_osl8192 + concurrency: 2048 iterations: 10 isl: 1024 osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu1 +- name: openai_gpt_oss_120b_1024_8192_conc4_gpu2 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 2 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 4 cuda_graph_config: enable_padding: true max_batch_size: 4 - enable_attention_dp: false + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + num_postprocess_workers: 4 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl8192_osl1024 + - name: con4_isl1024_osl8192 concurrency: 4 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu1 +- name: openai_gpt_oss_120b_1024_8192_conc256_gpu2 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 2 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 256 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + num_postprocess_workers: 4 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 + - name: con256_isl1024_osl8192 + concurrency: 256 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu1 +- name: openai_gpt_oss_120b_1024_8192_conc10_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 10 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 10 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + num_postprocess_workers: 4 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con10_isl1024_osl8192 + concurrency: 10 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu2 +- name: openai_gpt_oss_120b_1024_8192_conc128_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 128 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + num_postprocess_workers: 4 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con128_isl1024_osl8192 + concurrency: 128 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu2 +- name: openai_gpt_oss_120b_1024_8192_conc896_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 896 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 896 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + num_postprocess_workers: 4 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 + - name: con896_isl1024_osl8192 + concurrency: 896 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu2 +- name: openai_gpt_oss_120b_8192_1024_conc1_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 1 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 1 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + num_postprocess_workers: 4 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con1_isl8192_osl1024 + concurrency: 1 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu4 +- name: openai_gpt_oss_120b_8192_1024_conc32_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 32 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 32 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con32_isl8192_osl1024 + concurrency: 32 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu4 +- name: openai_gpt_oss_120b_8192_1024_conc1792_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 1792 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 1792 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 + - name: con1792_isl8192_osl1024 + concurrency: 1792 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu4 +- name: openai_gpt_oss_120b_8192_1024_conc8_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 4 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 8 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 8 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + num_postprocess_workers: 4 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con8_isl8192_osl1024 + concurrency: 8 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu8 +- name: openai_gpt_oss_120b_8192_1024_conc128_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 128 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con128_isl8192_osl1024 + concurrency: 128 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu8 +- name: openai_gpt_oss_120b_8192_1024_conc2048_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario @@ -1776,61 +1389,98 @@ server_configs: NCCL_GRAPH_REGISTER: 0 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 2048 + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 - num_postprocess_workers: 4 moe_config: backend: TRTLLM + num_postprocess_workers: 4 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 + - name: con2048_isl8192_osl1024 + concurrency: 2048 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu8 +- name: openai_gpt_oss_120b_8192_1024_conc768_gpu2 model_name: gpt_oss_120b_fp4 - gpus: 8 + gpus: 2 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 NCCL_GRAPH_REGISTER: 0 + max_batch_size: 384 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 384 + enable_attention_dp: true + print_iter_log: true kv_cache_config: dtype: fp8 free_gpu_memory_fraction: 0.85 enable_block_reuse: false - print_iter_log: true stream_interval: 20 + moe_config: + backend: TRTLLM + attention_dp_config: + enable_balance: true num_postprocess_workers: 4 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 + trust_remote_code: true + max_num_tokens: 20000 + max_seq_len: 9236 + client_configs: + - name: con768_isl8192_osl1024 + concurrency: 768 + iterations: 10 + isl: 8192 + osl: 1024 + random_range_ratio: 0.0 + backend: openai + streaming: true +- name: openai_gpt_oss_120b_8192_1024_conc1280_gpu2 + model_name: gpt_oss_120b_fp4 + gpus: 2 + match_mode: scenario + env_overrides: + TRTLLM_ENABLE_PDL: 1 + NCCL_GRAPH_REGISTER: 0 + max_batch_size: 640 + cuda_graph_config: + enable_padding: true + max_batch_size: 640 + enable_attention_dp: true + print_iter_log: true + kv_cache_config: + dtype: fp8 + free_gpu_memory_fraction: 0.85 + enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRTLLM - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 + attention_dp_config: + enable_balance: true + num_postprocess_workers: 4 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con1280_isl8192_osl1024 + concurrency: 1280 iterations: 10 isl: 8192 osl: 1024 diff --git a/tests/scripts/perf-sanity/config_database_h200_sxm.yaml b/tests/scripts/perf-sanity/aggregated/config_database_h200_sxm.yaml similarity index 50% rename from tests/scripts/perf-sanity/config_database_h200_sxm.yaml rename to tests/scripts/perf-sanity/aggregated/config_database_h200_sxm.yaml index f8e3d7bd294e..9179ca664585 100644 --- a/tests/scripts/perf-sanity/config_database_h200_sxm.yaml +++ b/tests/scripts/perf-sanity/aggregated/config_database_h200_sxm.yaml @@ -1,74 +1,79 @@ server_configs: -- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc4_gpu8 +- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc1_gpu8 model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 128 - enable_attention_dp: false + max_batch_size: 1 print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.75 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false stream_interval: 10 moe_config: backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 + max_num_tokens: 3136 max_seq_len: 2068 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1_isl1024_osl1024 + concurrency: 1 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc16_gpu8 +- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc32_gpu8 model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 1024 cuda_graph_config: enable_padding: true - max_batch_size: 128 - enable_attention_dp: false + max_batch_size: 1024 print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.75 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false stream_interval: 10 moe_config: backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 + max_num_tokens: 5248 max_seq_len: 2068 client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 + - name: con32_isl1024_osl1024 + concurrency: 32 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc64_gpu8 +- name: deepseek_ai_DeepSeek_R1_0528_1024_1024_conc2048_gpu8 model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 128 - enable_attention_dp: false + max_batch_size: 512 + enable_attention_dp: true print_iter_log: true kv_cache_config: dtype: fp8 @@ -77,90 +82,100 @@ server_configs: stream_interval: 10 moe_config: backend: CUTLASS + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 1152 + max_num_tokens: 2112 max_seq_len: 2068 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con2048_isl1024_osl1024 + concurrency: 2048 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc4_gpu8 +- name: deepseek_ai_DeepSeek_R1_0528_1024_8192_conc1_gpu8 model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 128 - enable_attention_dp: false + max_batch_size: 1 print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.75 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false stream_interval: 10 moe_config: backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 3136 max_seq_len: 9416 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con1_isl1024_osl8192 + concurrency: 1 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc16_gpu8 +- name: deepseek_ai_DeepSeek_R1_0528_1024_8192_conc16_gpu8 model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 128 - enable_attention_dp: false + max_batch_size: 16 print_iter_log: true kv_cache_config: dtype: fp8 - free_gpu_memory_fraction: 0.75 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false stream_interval: 10 moe_config: backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 3136 max_seq_len: 9416 client_configs: - - name: con16_isl8192_osl1024 + - name: con16_isl1024_osl8192 concurrency: 16 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc64_gpu8 +- name: deepseek_ai_DeepSeek_R1_0528_1024_8192_conc512_gpu8 model_name: deepseek_r1_0528_fp8 gpus: 8 match_mode: scenario + max_batch_size: 128 cuda_graph_config: enable_padding: true - max_batch_size: 128 enable_attention_dp: true print_iter_log: true kv_cache_config: @@ -174,135 +189,132 @@ server_configs: batching_wait_iters: 0 enable_balance: true timeout_iters: 60 + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 1 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 8320 + max_num_tokens: 1344 max_seq_len: 9416 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con512_isl1024_osl8192 + concurrency: 512 iterations: 10 - isl: 8192 - osl: 1024 + isl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 +- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc1_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 1 + print_iter_log: true kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 + dtype: fp8 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false + stream_interval: 10 moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 + max_num_tokens: 10304 + max_seq_len: 9416 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1_isl8192_osl1024 + concurrency: 1 iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 +- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc16_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 + max_batch_size: 512 cuda_graph_config: enable_padding: true max_batch_size: 16 - enable_attention_dp: false + print_iter_log: true kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 + dtype: fp8 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false + stream_interval: 10 moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 + max_num_tokens: 10304 + max_seq_len: 9416 client_configs: - - name: con16_isl1024_osl1024 + - name: con16_isl8192_osl1024 concurrency: 16 iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 +- name: deepseek_ai_DeepSeek_R1_0528_8192_1024_conc256_gpu8 + model_name: deepseek_r1_0528_fp8 + gpus: 8 match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 256 + print_iter_log: true kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 + dtype: fp8 + free_gpu_memory_fraction: 0.8 enable_block_reuse: false + stream_interval: 10 moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + backend: CUTLASS + speculative_config: + decoding_type: MTP + num_nextn_predict_layers: 3 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 2068 + max_num_tokens: 10304 + max_seq_len: 9416 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con256_isl8192_osl1024 + concurrency: 256 iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu2 +- name: openai_gpt_oss_120b_1024_1024_conc4_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 cuda_graph_config: enable_padding: true max_batch_size: 4 - enable_attention_dp: false kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false moe_config: @@ -310,10 +322,9 @@ server_configs: num_postprocess_workers: 4 print_iter_log: true stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: @@ -325,18 +336,16 @@ server_configs: random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu2 +- name: openai_gpt_oss_120b_1024_1024_conc64_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 64 kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false moe_config: @@ -344,690 +353,427 @@ server_configs: num_postprocess_workers: 4 print_iter_log: true stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 + - name: con64_isl1024_osl1024 + concurrency: 64 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu2 +- name: openai_gpt_oss_120b_1024_1024_conc2048_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 256 + enable_attention_dp: true + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON + attention_dp_config: + enable_balance: true num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con2048_isl1024_osl1024 + concurrency: 2048 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu4 +- name: openai_gpt_oss_120b_1024_1024_conc128_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 128 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con128_isl1024_osl1024 + concurrency: 128 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu4 +- name: openai_gpt_oss_120b_1024_1024_conc384_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 384 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 384 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 + - name: con384_isl1024_osl1024 + concurrency: 384 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu4 +- name: openai_gpt_oss_120b_1024_1024_conc1024_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 1024 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 1024 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 2068 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con1024_isl1024_osl1024 + concurrency: 1024 iterations: 10 isl: 1024 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc4_gpu8 +- name: openai_gpt_oss_120b_1024_8192_conc1_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 1 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 1 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 2068 + max_seq_len: 9236 client_configs: - - name: con4_isl1024_osl1024 - concurrency: 4 + - name: con1_isl1024_osl8192 + concurrency: 1 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc16_gpu8 +- name: openai_gpt_oss_120b_1024_8192_conc64_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 64 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 64 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 2068 + max_seq_len: 9236 client_configs: - - name: con16_isl1024_osl1024 - concurrency: 16 + - name: con64_isl1024_osl8192 + concurrency: 64 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_1024_conc64_gpu8 +- name: openai_gpt_oss_120b_1024_8192_conc1280_gpu8 model_name: gpt_oss_120b_fp4 gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 1280 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false + max_batch_size: 1280 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 8 moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 - max_seq_len: 2068 + max_seq_len: 9236 client_configs: - - name: con64_isl1024_osl1024 - concurrency: 64 + - name: con1280_isl1024_osl8192 + concurrency: 1280 iterations: 10 isl: 1024 - osl: 1024 + osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu1 +- name: openai_gpt_oss_120b_1024_8192_conc512_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 512 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 512 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 + - name: con512_isl1024_osl8192 + concurrency: 512 iterations: 10 isl: 1024 osl: 8192 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu1 +- name: openai_gpt_oss_120b_8192_1024_conc1_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 1 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 1 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 + - name: con1_isl8192_osl1024 + concurrency: 1 iterations: 10 - isl: 1024 - osl: 8192 + isl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu1 +- name: openai_gpt_oss_120b_8192_1024_conc64_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 64 cuda_graph_config: enable_padding: true max_batch_size: 64 - enable_attention_dp: false + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl1024_osl8192 + - name: con64_isl8192_osl1024 concurrency: 64 iterations: 10 - isl: 1024 - osl: 8192 + isl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu2 +- name: openai_gpt_oss_120b_8192_1024_conc1536_gpu8 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 8 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 1536 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false + max_batch_size: 1536 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 + - name: con1536_isl8192_osl1024 + concurrency: 1536 iterations: 10 - isl: 1024 - osl: 8192 + isl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu2 +- name: openai_gpt_oss_120b_8192_1024_conc2_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 2 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 2 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 2 + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 4 moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 + - name: con2_isl8192_osl1024 + concurrency: 2 iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 8192 + isl: 8192 + osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu4 +- name: openai_gpt_oss_120b_8192_1024_conc4_gpu4 model_name: gpt_oss_120b_fp4 gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc4_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 + max_batch_size: 4 cuda_graph_config: enable_padding: true max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con4_isl1024_osl8192 - concurrency: 4 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc16_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl1024_osl8192 - concurrency: 16 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_1024_8192_conc64_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true stream_interval: 20 - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con64_isl1024_osl8192 - concurrency: 64 - iterations: 10 - isl: 1024 - osl: 8192 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: @@ -1039,102 +785,32 @@ server_configs: random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu1 +- name: openai_gpt_oss_120b_8192_1024_conc768_gpu4 model_name: gpt_oss_120b_fp4 - gpus: 1 + gpus: 4 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 768 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 + max_batch_size: 768 print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu1 - model_name: gpt_oss_120b_fp4 - gpus: 1 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true stream_interval: 20 - tensor_parallel_size: 1 - moe_expert_parallel_size: 1 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu2 - model_name: gpt_oss_120b_fp4 - gpus: 2 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 + - name: con768_isl8192_osl1024 + concurrency: 768 iterations: 10 isl: 8192 osl: 1024 @@ -1147,23 +823,22 @@ server_configs: match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 8 cuda_graph_config: enable_padding: true - max_batch_size: 16 - enable_attention_dp: false + max_batch_size: 8 + enable_attention_dp: true + print_iter_log: true kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false + stream_interval: 20 moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 tensor_parallel_size: 2 moe_expert_parallel_size: 2 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: @@ -1175,238 +850,64 @@ server_configs: random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu2 +- name: openai_gpt_oss_120b_8192_1024_conc256_gpu2 model_name: gpt_oss_120b_fp4 gpus: 2 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 256 cuda_graph_config: enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 + max_batch_size: 256 print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 2 - moe_expert_parallel_size: 2 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true stream_interval: 20 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu4 - model_name: gpt_oss_120b_fp4 - gpus: 4 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con256_isl8192_osl1024 + concurrency: 256 iterations: 10 isl: 8192 osl: 1024 random_range_ratio: 0.0 backend: openai streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc4_gpu8 +- name: openai_gpt_oss_120b_8192_1024_conc384_gpu2 model_name: gpt_oss_120b_fp4 - gpus: 8 + gpus: 2 match_mode: scenario env_overrides: TRTLLM_ENABLE_PDL: 1 + max_batch_size: 384 cuda_graph_config: enable_padding: true - max_batch_size: 4 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 + max_batch_size: 384 print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con4_isl8192_osl1024 - concurrency: 4 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc16_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 16 - enable_attention_dp: false kv_cache_config: - dtype: auto free_gpu_memory_fraction: 0.85 enable_block_reuse: false - moe_config: - backend: TRITON - num_postprocess_workers: 4 - print_iter_log: true stream_interval: 20 - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - trust_remote_code: true - backend: pytorch - max_num_tokens: 20000 - max_seq_len: 9236 - client_configs: - - name: con16_isl8192_osl1024 - concurrency: 16 - iterations: 10 - isl: 8192 - osl: 1024 - random_range_ratio: 0.0 - backend: openai - streaming: true -- name: openai_gpt_oss_120b_8192_1024_conc64_gpu8 - model_name: gpt_oss_120b_fp4 - gpus: 8 - match_mode: scenario - env_overrides: - TRTLLM_ENABLE_PDL: 1 - cuda_graph_config: - enable_padding: true - max_batch_size: 64 - enable_attention_dp: false - kv_cache_config: - dtype: auto - free_gpu_memory_fraction: 0.85 - enable_block_reuse: false moe_config: backend: TRITON num_postprocess_workers: 4 - print_iter_log: true - stream_interval: 20 - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 trust_remote_code: true - backend: pytorch max_num_tokens: 20000 max_seq_len: 9236 client_configs: - - name: con64_isl8192_osl1024 - concurrency: 64 + - name: con384_isl8192_osl1024 + concurrency: 384 iterations: 10 isl: 8192 osl: 1024 diff --git a/tests/scripts/perf-sanity/deepseek_r1_fp8_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml similarity index 51% rename from tests/scripts/perf-sanity/deepseek_r1_fp8_blackwell.yaml rename to tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml index 6ff3d94545f9..937356b9ce44 100644 --- a/tests/scripts/perf-sanity/deepseek_r1_fp8_blackwell.yaml +++ b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml @@ -1,11 +1,14 @@ metadata: - model_name: deepseek_r1_0528_fp8 + model_name: deepseek_r1_0528_fp4_v2 supported_gpus: - - B200 - - B300 + - GB200 +hardware: + gpus_per_node: 4 server_configs: - - name: "r1_fp8_dep8_mtp1_1k1k" - model_name: "deepseek_r1_0528_fp8" + # 1k1k configs - DEP8 with CUTLASS, MTP1 + - name: "r1_fp4_v2_dep8_mtp1_1k1k" + model_name: "deepseek_r1_0528_fp4_v2" + trust_remote_code: true tensor_parallel_size: 8 moe_expert_parallel_size: 8 pipeline_parallel_size: 1 @@ -18,7 +21,7 @@ server_configs: enable_balance: true timeout_iters: 60 moe_config: - backend: 'DEEPGEMM' + backend: 'CUTLASS' cuda_graph_config: enable_padding: true max_batch_size: 512 @@ -30,70 +33,77 @@ server_configs: decoding_type: 'MTP' num_nextn_predict_layers: 1 client_configs: - - name: "con4096_iter5_1k1k" - concurrency: 4096 - iterations: 5 + - name: "con1024_iter10_1k1k" + concurrency: 1024 + iterations: 10 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json - - name: "r1_fp8_tep8_mtp3_1k1k" - model_name: "deepseek_r1_0528_fp8" + # 8k1k configs - DEP8 with CUTLASS, MTP1 + - name: "r1_fp4_v2_dep8_mtp1_8k1k" + model_name: "deepseek_r1_0528_fp4_v2" + trust_remote_code: true tensor_parallel_size: 8 moe_expert_parallel_size: 8 pipeline_parallel_size: 1 - max_batch_size: 64 - max_num_tokens: 8192 + max_batch_size: 512 + max_num_tokens: 12288 attn_backend: "TRTLLM" - enable_attention_dp: false + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 moe_config: - backend: 'DEEPGEMM' + backend: 'CUTLASS' cuda_graph_config: enable_padding: true - max_batch_size: 64 + max_batch_size: 512 kv_cache_config: dtype: 'fp8' enable_block_reuse: false free_gpu_memory_fraction: 0.8 speculative_config: decoding_type: 'MTP' - num_nextn_predict_layers: 3 + num_nextn_predict_layers: 1 client_configs: - - name: "con64_iter10_1k1k" - concurrency: 64 + - name: "con1024_iter10_8k1k" + concurrency: 1024 iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json - - name: "r1_fp8_tp8_mtp3_1k1k" - model_name: "deepseek_r1_0528_fp8" + # 1k1k configs - TEP8 with TRTLLM, MTP3 + - name: "r1_fp4_v2_tep8_mtp3" + model_name: "deepseek_r1_0528_fp4_v2" + trust_remote_code: true tensor_parallel_size: 8 - moe_expert_parallel_size: 1 + moe_expert_parallel_size: 8 pipeline_parallel_size: 1 - max_batch_size: 8 - max_num_tokens: 8192 + max_batch_size: 512 + max_num_tokens: 3136 attn_backend: "TRTLLM" enable_attention_dp: false moe_config: - backend: 'TRTLLM' + backend: "TRTLLM" cuda_graph_config: enable_padding: true - max_batch_size: 8 + max_batch_size: 512 kv_cache_config: dtype: 'fp8' - enable_block_reuse: false - free_gpu_memory_fraction: 0.8 + free_gpu_memory_fraction: 0.5 speculative_config: decoding_type: 'MTP' num_nextn_predict_layers: 3 client_configs: - - name: "con8_iter10_1k1k" - concurrency: 8 - iterations: 10 + - name: "con32_iter12_1k1k" + concurrency: 32 + iterations: 12 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_blackwell.yaml new file mode 100644 index 000000000000..588fdf4286e5 --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_blackwell.yaml @@ -0,0 +1,138 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + supported_gpus: + - B200 +hardware: + gpus_per_node: 8 +server_configs: + # 1k1k configs - TP4 with TRTLLM, MTP3 + - name: "r1_fp4_v2_tp4_mtp3_1k1k" + model_name: "deepseek_r1_0528_fp4_v2" + tensor_parallel_size: 4 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con2_iter10_1k1k" + concurrency: 2 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json + + # 1k1k configs - DEP8 with CUTLASS, MTP1 + - name: "r1_fp4_v2_dep8_mtp1_1k1k" + model_name: "deepseek_r1_0528_fp4_v2" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 128 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 128 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con1024_iter10_1k1k" + concurrency: 1024 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - TP4 with TRTLLM, MTP3 + - name: "r1_fp4_v2_tp4_mtp3_8k1k" + model_name: "deepseek_r1_0528_fp4_v2" + tensor_parallel_size: 4 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con4_iter10_8k1k" + concurrency: 4 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - DEP8 with CUTLASS, MTP1 + - name: "r1_fp4_v2_dep8_mtp1_8k1k" + model_name: "deepseek_r1_0528_fp4_v2" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 32 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_grace_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_grace_blackwell.yaml similarity index 82% rename from tests/scripts/perf-sanity/deepseek_r1_fp4_v2_grace_blackwell.yaml rename to tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_grace_blackwell.yaml index 46c89fe768fa..8ba596e9b334 100644 --- a/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_grace_blackwell.yaml +++ b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp4_v2_grace_blackwell.yaml @@ -3,8 +3,10 @@ metadata: supported_gpus: - GB200 - GB300 +hardware: + gpus_per_node: 4 server_configs: - # 1k1k configs + # 1k1k configs - DEP4 with CUTLASS, MTP1 - name: "r1_fp4_v2_dep4_mtp1_1k1k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -31,14 +33,15 @@ server_configs: decoding_type: 'MTP' num_nextn_predict_layers: 1 client_configs: - - name: "con2048_iter5_1k1k" - concurrency: 2048 - iterations: 5 + - name: "con1024_iter10_1k1k" + concurrency: 1024 + iterations: 10 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json + # 1k1k configs - TEP4 with TRTLLM, MTP3 - name: "r1_fp4_v2_tep4_mtp3_1k1k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -66,9 +69,10 @@ server_configs: iterations: 10 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json + # 1k1k configs - TP4 with TRTLLM, MTP3 - name: "r1_fp4_v2_tp4_mtp3_1k1k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -91,15 +95,15 @@ server_configs: decoding_type: 'MTP' num_nextn_predict_layers: 3 client_configs: - - name: "con4_iter10_1k1k" - concurrency: 4 + - name: "con2_iter10_1k1k" + concurrency: 2 iterations: 10 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json - # 8k1k configs + # 8k1k configs - DEP4 with CUTLASS, MTP1 - name: "r1_fp4_v2_dep4_mtp1_8k1k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -126,14 +130,15 @@ server_configs: decoding_type: 'MTP' num_nextn_predict_layers: 1 client_configs: - - name: "con2048_iter5_8k1k" - concurrency: 2048 - iterations: 5 + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 isl: 8192 osl: 1024 - random_range_ratio: 0.2 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json + # 8k1k configs - TEP4 with TRTLLM, MTP3 - name: "r1_fp4_v2_tep4_mtp3_8k1k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -161,9 +166,10 @@ server_configs: iterations: 10 isl: 8192 osl: 1024 - random_range_ratio: 0.2 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json + # 8k1k configs - TP4 with TRTLLM, MTP3 - name: "r1_fp4_v2_tp4_mtp3_8k1k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -186,15 +192,15 @@ server_configs: decoding_type: 'MTP' num_nextn_predict_layers: 3 client_configs: - - name: "con4_iter10_8k1k" - concurrency: 4 + - name: "con2_iter10_8k1k" + concurrency: 2 iterations: 10 isl: 8192 osl: 1024 - random_range_ratio: 0.2 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json - # 1k8k configs + # 1k8k configs - DEP4 with CUTLASS, MTP1 - name: "r1_fp4_v2_dep4_mtp1_1k8k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -226,9 +232,10 @@ server_configs: iterations: 5 isl: 1024 osl: 8192 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k8k-20480-ratio-1_for_serve.json + # 1k8k configs - TEP4 with TRTLLM, MTP3 - name: "r1_fp4_v2_tep4_mtp3_1k8k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -256,9 +263,10 @@ server_configs: iterations: 10 isl: 1024 osl: 8192 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k8k-20480-ratio-1_for_serve.json + # 1k8k configs - TP4 with TRTLLM, MTP3 - name: "r1_fp4_v2_tp4_mtp3_1k8k" model_name: "deepseek_r1_0528_fp4_v2" tensor_parallel_size: 4 @@ -286,5 +294,5 @@ server_configs: iterations: 10 isl: 1024 osl: 8192 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k8k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp8_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp8_blackwell.yaml new file mode 100644 index 000000000000..8be30076a811 --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/deepseek_r1_fp8_blackwell.yaml @@ -0,0 +1,166 @@ +metadata: + model_name: deepseek_r1_0528_fp8 + supported_gpus: + - B200 +hardware: + gpus_per_node: 8 +server_configs: + # 1k1k configs - TP8 with TRTLLM, MTP3 + - name: "r1_fp8_tp8_mtp3_1k1k" + model_name: "deepseek_r1_0528_fp8" + tensor_parallel_size: 8 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 8 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 8 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con4_iter10_1k1k" + concurrency: 4 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json + + # 1k1k configs - DEP8 with DEEPGEMM, MTP1 + - name: "r1_fp8_dep8_mtp1_1k1k" + model_name: "deepseek_r1_0528_fp8" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 128 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'DEEPGEMM' + cuda_graph_config: + enable_padding: true + max_batch_size: 128 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con1024_iter10_1k1k" + concurrency: 1024 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - TP8 with TRTLLM, MTP3 + - name: "r1_fp8_tp8_mtp3_8k1k" + model_name: "deepseek_r1_0528_fp8" + tensor_parallel_size: 8 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 8 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 8 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con4_iter10_8k1k" + concurrency: 4 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - DEP8 with DEEPGEMM, MTP1 + - name: "r1_fp8_dep8_mtp1_8k1k" + model_name: "deepseek_r1_0528_fp8" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 32 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'DEEPGEMM' + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json + + # 6k1k configs - TP8 with TRTLLM, MTP1 + - name: "r1_fp8_tp8_6k1k" + model_name: "deepseek_r1_0528_fp8" + tensor_parallel_size: 8 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + client_configs: + - name: "con64_iter10_6k1k" + concurrency: 64 + iterations: 10 + isl: 6144 + osl: 1024 + backend: "openai" + random_range_ratio: 0.2 diff --git a/tests/scripts/perf-sanity/aggregated/deepseek_v32_fp4_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/deepseek_v32_fp4_blackwell.yaml new file mode 100644 index 000000000000..7835cce594eb --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/deepseek_v32_fp4_blackwell.yaml @@ -0,0 +1,72 @@ +metadata: + model_name: deepseek_v32_fp4 + supported_gpus: + - B200 +hardware: + gpus_per_node: 8 +server_configs: + # 8k1k configs - TEP8 with TRTLLM, MTP3 + - name: "v32_fp4_tep8_mtp3_8k1k" + model_name: "deepseek_v32_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con2_iter10_8k1k" + concurrency: 2 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - DEP8 with CUTLASS, MTP1 + - name: "v32_fp4_dep8_mtp1_8k1k" + model_name: "deepseek_v32_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 32 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/aggregated/deepseek_v32_fp4_grace_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/deepseek_v32_fp4_grace_blackwell.yaml new file mode 100644 index 000000000000..591303abb6c7 --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/deepseek_v32_fp4_grace_blackwell.yaml @@ -0,0 +1,138 @@ +metadata: + model_name: deepseek_v32_fp4 + supported_gpus: + - GB200 +hardware: + gpus_per_node: 4 +server_configs: + # 1k1k configs - TEP4 with TRTLLM, MTP3 + - name: "v32_fp4_tep4_mtp3_1k1k" + model_name: "deepseek_v32_fp4" + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con2_iter10_1k1k" + concurrency: 2 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_v32-1k1k-20480-ratio-1_for_serve.json + + # 1k1k configs - DEP4 with CUTLASS, MTP1 + - name: "v32_fp4_dep4_mtp1_1k1k" + model_name: "deepseek_v32_fp4" + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + max_batch_size: 256 + max_num_tokens: 8192 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 256 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con1024_iter10_1k1k" + concurrency: 1024 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_v32-1k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - TEP4 with TRTLLM, MTP3 + - name: "v32_fp4_tep4_mtp3_8k1k" + model_name: "deepseek_v32_fp4" + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 3 + client_configs: + - name: "con2_iter10_8k1k" + concurrency: 2 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - DEP4 with CUTLASS, MTP1 + - name: "v32_fp4_dep4_mtp1_8k1k" + model_name: "deepseek_v32_fp4" + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + max_batch_size: 64 + max_num_tokens: 12288 + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + speculative_config: + decoding_type: 'MTP' + num_nextn_predict_layers: 1 + client_configs: + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/gb300_deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml similarity index 57% rename from tests/scripts/perf-sanity/deepseek_r1_fp4_v2_blackwell.yaml rename to tests/scripts/perf-sanity/aggregated/gb300_deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml index 8661c2413984..f92bdca6a3d8 100644 --- a/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_blackwell.yaml +++ b/tests/scripts/perf-sanity/aggregated/gb300_deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml @@ -1,13 +1,16 @@ metadata: model_name: deepseek_r1_0528_fp4_v2 supported_gpus: - - B200 - - B300 + - GB300 +hardware: + gpus_per_node: 4 server_configs: - - name: "r1_fp4_v2_dep4_mtp1_1k1k" + # 1k1k configs - DEP8 with CUTLASS, MTP1 + - name: "r1_fp4_v2_dep8_mtp1_1k1k" model_name: "deepseek_r1_0528_fp4_v2" - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + trust_remote_code: true + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 pipeline_parallel_size: 1 max_batch_size: 512 max_num_tokens: 8192 @@ -30,69 +33,76 @@ server_configs: decoding_type: 'MTP' num_nextn_predict_layers: 1 client_configs: - - name: "con2048_iter5_1k1k" - concurrency: 2048 - iterations: 5 + - name: "con1024_iter10_1k1k" + concurrency: 1024 + iterations: 10 isl: 1024 osl: 1024 - random_range_ratio: 0.8 + random_range_ratio: 0.2 backend: "openai" - - name: "r1_fp4_v2_tep4_mtp3_1k1k" + # 8k1k configs - DEP8 with CUTLASS, MTP1 + - name: "r1_fp4_v2_dep8_mtp1_8k1k" model_name: "deepseek_r1_0528_fp4_v2" - tensor_parallel_size: 4 - moe_expert_parallel_size: 4 + trust_remote_code: true + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 pipeline_parallel_size: 1 - max_batch_size: 32 - max_num_tokens: 8192 + max_batch_size: 512 + max_num_tokens: 12288 attn_backend: "TRTLLM" - enable_attention_dp: false + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 moe_config: - backend: 'TRTLLM' + backend: 'CUTLASS' cuda_graph_config: enable_padding: true - max_batch_size: 32 + max_batch_size: 512 kv_cache_config: dtype: 'fp8' enable_block_reuse: false free_gpu_memory_fraction: 0.8 speculative_config: decoding_type: 'MTP' - num_nextn_predict_layers: 3 + num_nextn_predict_layers: 1 client_configs: - - name: "con32_iter10_1k1k" - concurrency: 32 + - name: "con1024_iter10_8k1k" + concurrency: 1024 iterations: 10 - isl: 1024 + isl: 8192 osl: 1024 - random_range_ratio: 0.8 + random_range_ratio: 0.2 backend: "openai" - - name: "r1_fp4_v2_tp4_mtp3_1k1k" + # 1k1k configs - TEP8 with TRTLLM, MTP3 + - name: "r1_fp4_v2_tep8_mtp3" model_name: "deepseek_r1_0528_fp4_v2" - tensor_parallel_size: 4 - moe_expert_parallel_size: 1 + trust_remote_code: true + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 pipeline_parallel_size: 1 - max_batch_size: 4 - max_num_tokens: 8192 + max_batch_size: 512 + max_num_tokens: 3136 attn_backend: "TRTLLM" enable_attention_dp: false moe_config: - backend: 'TRTLLM' + backend: "TRTLLM" cuda_graph_config: enable_padding: true - max_batch_size: 4 + max_batch_size: 512 kv_cache_config: dtype: 'fp8' - enable_block_reuse: false - free_gpu_memory_fraction: 0.8 + free_gpu_memory_fraction: 0.5 speculative_config: decoding_type: 'MTP' num_nextn_predict_layers: 3 client_configs: - - name: "con4_iter10_1k1k" - concurrency: 4 - iterations: 10 + - name: "con32_iter12_1k1k" + concurrency: 32 + iterations: 12 isl: 1024 osl: 1024 random_range_ratio: 0.8 diff --git a/tests/scripts/perf-sanity/aggregated/gpt_oss_120b_fp4_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/gpt_oss_120b_fp4_blackwell.yaml new file mode 100644 index 000000000000..cde7a71b2a2d --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/gpt_oss_120b_fp4_blackwell.yaml @@ -0,0 +1,103 @@ +metadata: + model_name: gpt_oss_120b_fp4 + supported_gpus: + - B200 +hardware: + gpus_per_node: 8 +server_configs: + # 1k1k configs - TP2 with TRTLLM, MTP0 + - name: "gpt_oss_fp4_tp2_mtp0_1k1k" + model_name: "gpt_oss_120b_fp4" + tensor_parallel_size: 2 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 20000 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + num_postprocess_workers: 4 + stream_interval: 20 + client_configs: + - name: "con4_iter10_1k1k" + concurrency: 4 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json + + # 1k1k configs - TP1 with TRTLLM, MTP0 + - name: "gpt_oss_fp4_tp1_mtp0_1k1k" + model_name: "gpt_oss_120b_fp4" + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 20000 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + num_postprocess_workers: 4 + stream_interval: 20 + client_configs: + - name: "con256_iter10_1k1k" + concurrency: 256 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - TP1 with TRTLLM, MTP0 + - name: "gpt_oss_fp4_tp1_mtp0_8k1k" + model_name: "gpt_oss_120b_fp4" + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 20000 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + num_postprocess_workers: 4 + stream_interval: 20 + client_configs: + - name: "con4_iter10_8k1k" + concurrency: 4 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/gpt_oss_120b_fp4_grace_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/gpt_oss_120b_fp4_grace_blackwell.yaml similarity index 54% rename from tests/scripts/perf-sanity/gpt_oss_120b_fp4_grace_blackwell.yaml rename to tests/scripts/perf-sanity/aggregated/gpt_oss_120b_fp4_grace_blackwell.yaml index d5993c46deb3..cc5dbe906753 100644 --- a/tests/scripts/perf-sanity/gpt_oss_120b_fp4_grace_blackwell.yaml +++ b/tests/scripts/perf-sanity/aggregated/gpt_oss_120b_fp4_grace_blackwell.yaml @@ -1,8 +1,9 @@ metadata: model_name: gpt_oss_120b_fp4 supported_gpus: - - B200 - - B300 + - GB200 +hardware: + gpus_per_node: 4 server_configs: - name: "gpt_oss_fp4_dep4_1k8k" model_name: "gpt_oss_120b_fp4" @@ -32,8 +33,8 @@ server_configs: iterations: 5 isl: 1024 osl: 8192 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k8k-20480-ratio-1_for_serve.json - name: "gpt_oss_fp4_dep2_1k1k" model_name: "gpt_oss_120b_fp4" @@ -63,8 +64,8 @@ server_configs: iterations: 5 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json - name: "gpt_oss_fp4_tep2_1k8k" model_name: "gpt_oss_120b_fp4" @@ -92,8 +93,8 @@ server_configs: iterations: 10 isl: 1024 osl: 8192 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k8k-20480-ratio-1_for_serve.json - name: "gpt_oss_fp4_tp2_1k8k" model_name: "gpt_oss_120b_fp4" @@ -121,8 +122,8 @@ server_configs: iterations: 10 isl: 1024 osl: 8192 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k8k-20480-ratio-1_for_serve.json - name: "gpt_oss_fp4_tp4_eagle3_1k1k" model_name: "gpt_oss_120b_fp4" @@ -155,5 +156,102 @@ server_configs: iterations: 32 isl: 1024 osl: 1024 - random_range_ratio: 0.8 backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json + + # GPT-OSS configs from Excel - 1k1k TP2 (TP2EP1) con4 + - name: "gpt_oss_fp4_tp2_mtp0_1k1k" + model_name: "gpt_oss_120b_fp4" + tensor_parallel_size: 2 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 20000 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + num_postprocess_workers: 4 + stream_interval: 20 + client_configs: + - name: "con4_iter10_1k1k" + concurrency: 4 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json + + # GPT-OSS configs from Excel - 1k1k TP1 con256 + - name: "gpt_oss_fp4_tp1_mtp0_1k1k" + model_name: "gpt_oss_120b_fp4" + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 20000 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + num_postprocess_workers: 4 + stream_interval: 20 + client_configs: + - name: "con256_iter10_1k1k" + concurrency: 256 + iterations: 10 + isl: 1024 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json + + # GPT-OSS configs from Excel - 8k1k TP1 con4 and con256 + - name: "gpt_oss_fp4_tp1_mtp0_8k1k" + model_name: "gpt_oss_120b_fp4" + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + max_batch_size: 512 + max_num_tokens: 20000 + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + num_postprocess_workers: 4 + stream_interval: 20 + client_configs: + - name: "con4_iter10_8k1k" + concurrency: 4 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_2_nodes_grace_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_2_nodes_grace_blackwell.yaml new file mode 100644 index 000000000000..d7f9a5cc728f --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_2_nodes_grace_blackwell.yaml @@ -0,0 +1,72 @@ +metadata: + model_name: k2_thinking_fp4 + supported_gpus: + - GB200 +hardware: + gpus_per_node: 4 +server_configs: + # 32k8k configs - TEP8 with TRTLLM + - name: "k2_thinking_fp4_tep8_32k8k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 8192 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_chunked_prefill: true + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con2_iter10_32k8k" + concurrency: 2 + iterations: 10 + isl: 32768 + osl: 8192 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-32k8k-20480-ratio-1_for_serve.json + + # 32k8k configs - DEP8 with CUTLASS + - name: "k2_thinking_fp4_dep8_32k8k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 32 + max_num_tokens: 8192 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_chunked_prefill: true + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con128_iter10_32k8k" + concurrency: 128 + iterations: 10 + isl: 32768 + osl: 8192 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-32k8k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_blackwell.yaml new file mode 100644 index 000000000000..10b5b26a86b3 --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_blackwell.yaml @@ -0,0 +1,136 @@ +metadata: + model_name: k2_thinking_fp4 + supported_gpus: + - B200 +hardware: + gpus_per_node: 8 +server_configs: + # 8k1k configs - TEP8 with TRTLLM + - name: "k2_thinking_fp4_tep8_8k1k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 12288 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con2_iter10_8k1k" + concurrency: 2 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - DEP8 with CUTLASS + - name: "k2_thinking_fp4_dep8_8k1k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 64 + max_num_tokens: 12288 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con512_iter10_8k1k" + concurrency: 512 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json + + # 32k8k configs - TEP8 with TRTLLM + - name: "k2_thinking_fp4_tep8_32k8k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 8192 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_chunked_prefill: true + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con2_iter10_32k8k" + concurrency: 2 + iterations: 10 + isl: 32768 + osl: 8192 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-32k8k-20480-ratio-1_for_serve.json + + # 32k8k configs - DEP8 with CUTLASS + - name: "k2_thinking_fp4_dep8_32k8k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + max_batch_size: 32 + max_num_tokens: 8192 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_chunked_prefill: true + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con128_iter10_32k8k" + concurrency: 128 + iterations: 10 + isl: 32768 + osl: 8192 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-32k8k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_grace_blackwell.yaml b/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_grace_blackwell.yaml new file mode 100644 index 000000000000..dbef10e3cbf1 --- /dev/null +++ b/tests/scripts/perf-sanity/aggregated/k2_thinking_fp4_grace_blackwell.yaml @@ -0,0 +1,70 @@ +metadata: + model_name: k2_thinking_fp4 + supported_gpus: + - GB200 +hardware: + gpus_per_node: 4 +server_configs: + # 8k1k configs - TEP4 with TRTLLM + - name: "k2_thinking_fp4_tep4_8k1k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + max_batch_size: 4 + max_num_tokens: 12288 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_attention_dp: false + moe_config: + backend: 'TRTLLM' + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con2_iter10_8k1k" + concurrency: 2 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json + + # 8k1k configs - DEP4 with CUTLASS + - name: "k2_thinking_fp4_dep4_8k1k" + model_name: "k2_thinking_fp4" + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + max_batch_size: 64 + max_num_tokens: 12288 + trust_remote_code: true + attn_backend: "TRTLLM" + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + moe_config: + backend: 'CUTLASS' + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + dtype: 'fp8' + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + client_configs: + - name: "con256_iter10_8k1k" + concurrency: 256 + iterations: 10 + isl: 8192 + osl: 1024 + backend: "openai" + trust_remote_code: true + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json diff --git a/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml b/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml deleted file mode 100644 index 0d663651ee39..000000000000 --- a/tests/scripts/perf-sanity/deepseek_r1_fp4_v2_2_nodes_grace_blackwell.yaml +++ /dev/null @@ -1,69 +0,0 @@ -metadata: - model_name: deepseek_r1_0528_fp4_v2 - supported_gpus: - - GB200 - - GB300 -hardware: - gpus_per_node: 4 -server_configs: - - name: "r1_fp4_v2_dep8_mtp1" - model_name: "deepseek_r1_0528_fp4_v2" - trust_remote_code: true - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - pipeline_parallel_size: 1 - max_batch_size: 512 - max_num_tokens: 3136 - attn_backend: "TRTLLM" - enable_attention_dp: true - attention_dp_config: - batching_wait_iters: 0 - enable_balance: true - timeout_iters: 60 - moe_config: - backend: 'CUTLASS' - cuda_graph_config: - enable_padding: true - max_batch_size: 512 - kv_cache_config: - dtype: 'fp8' - enable_block_reuse: false - free_gpu_memory_fraction: 0.5 - client_configs: - - name: "con32_iter12_1k1k" - concurrency: 32 - iterations: 12 - isl: 1024 - osl: 1024 - random_range_ratio: 0.8 - backend: "openai" - - - name: "r1_fp4_v2_tep8_mtp3" - model_name: "deepseek_r1_0528_fp4_v2" - trust_remote_code: true - tensor_parallel_size: 8 - moe_expert_parallel_size: 8 - pipeline_parallel_size: 1 - max_batch_size: 512 - max_num_tokens: 3136 - attn_backend: "TRTLLM" - enable_attention_dp: false - moe_config: - backend: "TRTLLM" - cuda_graph_config: - enable_padding: true - max_batch_size: 512 - kv_cache_config: - dtype: 'fp8' - free_gpu_memory_fraction: 0.5 - speculative_config: - decoding_type: 'MTP' - num_nextn_predict_layers: 3 - client_configs: - - name: "con32_iter12_1k1k" - concurrency: 32 - iterations: 12 - isl: 1024 - osl: 1024 - random_range_ratio: 0.8 - backend: "openai" diff --git a/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..f406982f0671 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,96 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - B200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:8 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 8 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 256 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con2048_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con2048_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..d92871914265 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con2048_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - B200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:8 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '2048' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 8 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 256 + max_num_tokens: 512 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 256 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con256_ctx1_dep4_gen1_dep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con256_ctx1_dep4_gen1_dep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..10346b399f16 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_1k1k_con256_ctx1_dep4_gen1_dep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - B200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:8 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '256' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 8 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 256 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con1536_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con1536_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..8bf5046d96a3 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con1536_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - B200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:8 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1536' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 8 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 192 + max_num_tokens: 384 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 192 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..0545a4f5d793 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,96 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - B200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:8 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 8 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 256 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con256_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con256_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..77cf540bcac6 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/b200_deepseek-r1-fp4_8k1k_con256_ctx1_dep4_gen1_dep8_eplb0_mtp1_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - B200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:8 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '256' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 8 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con128_ctx1_pp8_gen1_dep16_eplb0_mtp2_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con128_ctx1_pp8_gen1_dep16_eplb0_mtp2_ccb-UCX.yaml new file mode 100644 index 000000000000..288617016b17 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con128_ctx1_pp8_gen1_dep16_eplb0_mtp2_ccb-UCX.yaml @@ -0,0 +1,96 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 128k8k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '128' + input_length: 131072 + output_length: 8192 + dataset_file: datasets/perf-ci/deepseek_r1-128k8k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 8 + max_num_tokens: 32 + tensor_parallel_size: 16 + moe_expert_parallel_size: 16 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 8 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 131104 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 2 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 131104 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 8 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.3 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 131104 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con1_ctx1_pp8_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con1_ctx1_pp8_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..8730f9c9ad2e --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con1_ctx1_pp8_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,96 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 128k8k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 131072 + output_length: 8192 + dataset_file: datasets/perf-ci/deepseek_r1-128k8k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 4 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 131104 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 131104 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 8 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.3 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 131104 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con64_ctx1_pp8_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con64_ctx1_pp8_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..6001cd94297c --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_128k8k_con64_ctx1_pp8_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,96 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 128k8k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '64' + input_length: 131072 + output_length: 8192 + dataset_file: datasets/perf-ci/deepseek_r1-128k8k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 8 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 2 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 131104 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 131104 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 8 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.3 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 131104 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..023a4bee0c46 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..3dba0456a22c --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,93 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + - GB300 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k + config_index: -1 +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: "--gres=gpu:4" + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: true + multi_round: 8 + benchmark_ratio: 0.8 + streaming: true + concurrency_list: '1024' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: "TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes" + server_env_var: "TRTLLM_SERVER_DISABLE_GC=1" +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false +worker_config: + gen: + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + pipeline_parallel_size: 1 + context_parallel_size: 1 + max_batch_size: 768 + max_num_tokens: 768 + max_seq_len: 2068 + cuda_graph_config: + enable_padding: true + max_batch_size: 768 + print_iter_log: true + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTLASS + use_low_precision_moe_combine: true + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + stream_interval: 100 + num_postprocess_workers: 4 + ctx: + max_batch_size: 16 + max_num_tokens: 16896 + max_seq_len: 2044 + tensor_parallel_size: 4 + context_parallel_size: 1 + moe_expert_parallel_size: 4 + enable_attention_dp: true + pipeline_parallel_size: 1 + print_iter_log: true + cuda_graph_config: null + disable_overlap_scheduler: true + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.75 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..343256ea737e --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 128 + max_num_tokens: 512 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 128 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con3072_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con3072_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..fecfd0c9b60e --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_1k1k_con3072_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '3072' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 768 + max_num_tokens: 1536 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 768 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..f195391d47f5 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.75 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..fd74cf5fc5a1 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 128 + max_num_tokens: 512 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 128 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con4096_ctx1_dep4_gen1_dep16_eplb0_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con4096_ctx1_dep4_gen1_dep16_eplb0_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..6bc440bc7ba3 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-r1-fp4_8k1k_con4096_ctx1_dep4_gen1_dep16_eplb0_mtp1_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4096' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 256 + max_num_tokens: 512 + tensor_parallel_size: 16 + moe_expert_parallel_size: 16 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 256 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb256_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb256_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..065a4e3eef5b --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb256_mtp3_ccb-UCX.yaml @@ -0,0 +1,108 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_v32-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + load_balancer: + num_slots: 256 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..f393fe8c16df --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,105 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_v32-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 512 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con2048_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con2048_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..14ee30497a71 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_1k1k_con2048_ctx1_dep4_gen1_dep4_eplb0_mtp1_ccb-UCX.yaml @@ -0,0 +1,105 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '2048' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_v32-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 512 + max_num_tokens: 1024 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..75e40a71e3c8 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,105 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 32k4k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 32768 + output_length: 4096 + dataset_file: datasets/perf-ci/deepseek_v32-32k4k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 256 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 32784 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con2048_ctx1_dep4_gen1_dep32_eplb288_mtp1_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con2048_ctx1_dep4_gen1_dep32_eplb288_mtp1_ccb-UCX.yaml new file mode 100644 index 000000000000..1532c16be662 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con2048_ctx1_dep4_gen1_dep32_eplb288_mtp1_ccb-UCX.yaml @@ -0,0 +1,108 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 32k4k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '2048' + input_length: 32768 + output_length: 4096 + dataset_file: datasets/perf-ci/deepseek_v32-32k4k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 64 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + load_balancer: + num_slots: 288 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 1 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + ctx: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 32784 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con256_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con256_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..93a047c09259 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_32k4k_con256_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,105 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 32k4k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '256' + input_length: 32768 + output_length: 4096 + dataset_file: datasets/perf-ci/deepseek_v32-32k4k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 8 + max_num_tokens: 256 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 8 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.85 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + ctx: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 32784 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb256_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb256_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..a724179fc510 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb256_mtp3_ccb-UCX.yaml @@ -0,0 +1,108 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.75 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + load_balancer: + num_slots: 256 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..ca8db584e74f --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con1_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,105 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1 + max_num_tokens: 512 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con4096_ctx1_dep4_gen1_dep32_eplb256_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con4096_ctx1_dep4_gen1_dep32_eplb256_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..ee9948f72846 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_deepseek-v32-fp4_8k1k_con4096_ctx1_dep4_gen1_dep32_eplb256_mtp0_ccb-UCX.yaml @@ -0,0 +1,104 @@ +metadata: + model_name: deepseek_v32_fp4 + precision: fp4 + model_dir_name: DeepSeek-V3.2-FP4-v2 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4096' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_v32-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 128 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 128 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + load_balancer: + num_slots: 256 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + nvfp4_gemm_config: + allowed_backends: + - cutlass + - cublaslt + - cutedsl + - cuda_core + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + tokens_per_block: 64 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con2048_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con2048_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..5ae5902c87b7 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con2048_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,95 @@ +metadata: + model_name: gpt_oss_120b_fp4 + precision: fp4 + model_dir_name: GPT-OSS-120B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '2048' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1536 + max_num_tokens: 20000 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + cuda_graph_config: + enable_padding: true + max_batch_size: 1536 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 1024 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 20000 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 1024 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..e0ac186b2033 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,95 @@ +metadata: + model_name: gpt_oss_120b_fp4 + precision: fp4 + model_dir_name: GPT-OSS-120B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '512' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1536 + max_num_tokens: 20000 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + cuda_graph_config: + enable_padding: true + max_batch_size: 1536 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 1024 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 20000 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 1024 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con64_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con64_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..0acc76bb0aec --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_1k1k_con64_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,91 @@ +metadata: + model_name: gpt_oss_120b_fp4 + precision: fp4 + model_dir_name: GPT-OSS-120B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '64' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/gpt_oss_120b-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 256 + max_num_tokens: 20000 + tensor_parallel_size: 4 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 256 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 1024 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 20000 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 1024 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con128_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con128_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..196c915b00cd --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con128_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,91 @@ +metadata: + model_name: gpt_oss_120b_fp4 + precision: fp4 + model_dir_name: GPT-OSS-120B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '128' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1024 + max_num_tokens: 20000 + tensor_parallel_size: 4 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1024 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 8448 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 20000 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 8448 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con4_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con4_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..a1c940d944cc --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con4_ctx1_tp1_gen1_tp4_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,91 @@ +metadata: + model_name: gpt_oss_120b_fp4 + precision: fp4 + model_dir_name: GPT-OSS-120B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 1024 + max_num_tokens: 20000 + tensor_parallel_size: 4 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 1024 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 8448 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 20000 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 8448 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..667e345b8954 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_gpt-oss-120b-fp4_8k1k_con512_ctx1_tp1_gen1_dep2_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,95 @@ +metadata: + model_name: gpt_oss_120b_fp4 + precision: fp4 + model_dir_name: GPT-OSS-120B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '512' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/gpt_oss_120b-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 512 + max_num_tokens: 20000 + tensor_parallel_size: 2 + moe_expert_parallel_size: 2 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + attention_dp_config: + batching_wait_iters: 0 + enable_balance: true + timeout_iters: 60 + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 8448 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 20000 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 8448 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con2048_ctx1_dep4_gen1_dep32_eplb384_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con2048_ctx1_dep4_gen1_dep32_eplb384_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..1cc06715d9b2 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con2048_ctx1_dep4_gen1_dep32_eplb384_mtp0_ccb-UCX.yaml @@ -0,0 +1,98 @@ +metadata: + model_name: k2_thinking_fp4 + precision: fp4 + model_dir_name: Kimi-K2-Thinking-NVFP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '2048' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/k2_thinking-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 64 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: WIDEEP + load_balancer: + num_slots: 384 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 8192 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con4096_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con4096_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..d049701d6374 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con4096_ctx1_dep4_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,95 @@ +metadata: + model_name: k2_thinking_fp4 + precision: fp4 + model_dir_name: Kimi-K2-Thinking-NVFP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4096' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/k2_thinking-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 512 + max_num_tokens: 512 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 512 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: CUTLASS + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 8192 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con4_ctx1_dep4_gen1_tep4_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con4_ctx1_dep4_gen1_tep4_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..77f285c14180 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_1k1k_con4_ctx1_dep4_gen1_tep4_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,94 @@ +metadata: + model_name: k2_thinking_fp4 + precision: fp4 + model_dir_name: Kimi-K2-Thinking-NVFP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/k2_thinking-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 4 + max_num_tokens: 128 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 8192 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb416_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb416_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..7f64ef39347e --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con1024_ctx1_dep4_gen1_dep32_eplb416_mtp3_ccb-UCX.yaml @@ -0,0 +1,104 @@ +metadata: + model_name: k2_thinking_fp4 + precision: fp4 + model_dir_name: Kimi-K2-Thinking-NVFP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: WIDEEP + load_balancer: + num_slots: 416 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: Eagle + max_draft_len: 3 + eagle3_one_model: true + speculative_model: Kimi-K2-Thinking-NVFP4-Eagle3 + trust_remote_code: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 8768 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 + trust_remote_code: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con4096_ctx1_dep4_gen1_dep16_eplb384_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con4096_ctx1_dep4_gen1_dep16_eplb384_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..9ba96ccfd86b --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con4096_ctx1_dep4_gen1_dep16_eplb384_mtp0_ccb-UCX.yaml @@ -0,0 +1,98 @@ +metadata: + model_name: k2_thinking_fp4 + precision: fp4 + model_dir_name: Kimi-K2-Thinking-NVFP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 5 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4096' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 256 + max_num_tokens: 256 + tensor_parallel_size: 16 + moe_expert_parallel_size: 16 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 256 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: WIDEEP + load_balancer: + num_slots: 384 + layer_updates_per_iter: 1 + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 8768 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + trust_remote_code: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con4_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con4_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..a133bb9b885e --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_kimi-k2-thinking-fp4_8k1k_con4_ctx1_dep4_gen1_tep8_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,101 @@ +metadata: + model_name: k2_thinking_fp4 + precision: fp4 + model_dir_name: Kimi-K2-Thinking-NVFP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '4' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/k2_thinking-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 4 + max_num_tokens: 128 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 4 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.8 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: Eagle + max_draft_len: 3 + eagle3_one_model: true + speculative_model: Kimi-K2-Thinking-NVFP4-Eagle3 + trust_remote_code: true + num_postprocess_workers: 4 + stream_interval: 20 + allreduce_strategy: MNNVL + ctx: + print_iter_log: true + max_batch_size: 2 + max_num_tokens: 8768 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 + trust_remote_code: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_qwen3-235b-fp4_8k1k_con1024_ctx1_tp1_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_qwen3-235b-fp4_8k1k_con1024_ctx1_tp1_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..6b79f12fd74a --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_qwen3-235b-fp4_8k1k_con1024_ctx1_tp1_gen1_dep8_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,92 @@ +metadata: + model_name: qwen3_235b_a22b_fp4 + precision: fp4 + model_dir_name: Qwen3-235B-A22B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/qwen3_235b-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 128 + max_num_tokens: 128 + tensor_parallel_size: 8 + moe_expert_parallel_size: 8 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 128 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 4 + max_num_tokens: 32768 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb200_qwen3-235b-fp4_8k1k_con64_ctx1_tp1_gen1_tep4_eplb0_mtp0_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb200_qwen3-235b-fp4_8k1k_con64_ctx1_tp1_gen1_tep4_eplb0_mtp0_ccb-UCX.yaml new file mode 100644 index 000000000000..001b3f2b3975 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb200_qwen3-235b-fp4_8k1k_con64_ctx1_tp1_gen1_tep4_eplb0_mtp0_ccb-UCX.yaml @@ -0,0 +1,91 @@ +metadata: + model_name: qwen3_235b_a22b_fp4 + precision: fp4 + model_dir_name: Qwen3-235B-A22B-FP4 + supported_gpus: + - GB200 + script_file: disaggr_torch.slurm + benchmark_type: 8k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '64' + input_length: 8192 + output_length: 1024 + dataset_file: datasets/perf-ci/qwen3_235b-8k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 64 + max_num_tokens: 64 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: + enable_padding: true + max_batch_size: 64 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.9 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 4 + max_num_tokens: 32768 + tensor_parallel_size: 1 + moe_expert_parallel_size: 1 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: false + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 32768 + backend: UCX + disable_overlap_scheduler: true diff --git a/tests/scripts/perf-sanity/disaggregated/gb300_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml b/tests/scripts/perf-sanity/disaggregated/gb300_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml new file mode 100644 index 000000000000..95ef58484ee0 --- /dev/null +++ b/tests/scripts/perf-sanity/disaggregated/gb300_deepseek-r1-fp4_1k1k_con1024_ctx1_dep4_gen1_dep32_eplb0_mtp3_ccb-UCX.yaml @@ -0,0 +1,97 @@ +metadata: + model_name: deepseek_r1_0528_fp4_v2 + precision: fp4 + model_dir_name: DeepSeek-R1-0528-FP4-v2 + supported_gpus: + - GB300 + script_file: disaggr_torch.slurm + benchmark_type: 1k1k +slurm: + script_file: disaggr_torch.slurm + partition: + account: + job_time: 02:00:00 + job_name: unified-benchmark + extra_args: --gres=gpu:4 + numa_bind: true +benchmark: + mode: e2e + use_nv_sa_benchmark: false + multi_round: 10 + benchmark_ratio: 0.0 + streaming: true + concurrency_list: '1024' + input_length: 1024 + output_length: 1024 + dataset_file: datasets/perf-ci/deepseek_r1-1k1k-20480-ratio-1_for_serve.json +hardware: + gpus_per_node: 4 + num_ctx_servers: 1 + num_gen_servers: 1 +environment: + container_mount: + container_image: + model_path: + trtllm_repo: '' + build_wheel: false + work_dir: + worker_env_var: TLLM_LOG_LEVEL=INFO TRTLLM_SERVER_DISABLE_GC=1 TRTLLM_WORKER_DISABLE_GC=1 TRTLLM_ENABLE_PDL=1 ENROOT_ALLOW_DEV=yes + server_env_var: TRTLLM_SERVER_DISABLE_GC=1 +profiling: + nsys_on: false +accuracy: + enable_accuracy_test: false + model: local-completions + tasks: gsm8k + model_args_extra: num_concurrent=512,max_retries=3,tokenized_requests=false,timeout=1200,max_gen_toks=256,max_length=4096 +worker_config: + gen: + print_iter_log: true + max_batch_size: 32 + max_num_tokens: 128 + tensor_parallel_size: 32 + moe_expert_parallel_size: 32 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: + enable_padding: true + max_batch_size: 32 + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: CUTEDSL + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: &id001 + decoding_type: MTP + num_nextn_predict_layers: 3 + num_postprocess_workers: 4 + stream_interval: 20 + ctx: + print_iter_log: true + max_batch_size: 16 + max_num_tokens: 16384 + tensor_parallel_size: 4 + moe_expert_parallel_size: 4 + pipeline_parallel_size: 1 + context_parallel_size: 1 + enable_attention_dp: true + enable_lm_head_tp_in_adp: true + cuda_graph_config: null + kv_cache_config: + enable_block_reuse: false + free_gpu_memory_fraction: 0.6 + dtype: fp8 + moe_config: + backend: TRTLLM + cache_transceiver_config: + max_tokens_in_buffer: 16384 + backend: UCX + disable_overlap_scheduler: true + speculative_config: *id001 diff --git a/tests/test_common/error_utils.py b/tests/test_common/error_utils.py new file mode 100644 index 000000000000..9cb57aaf88f7 --- /dev/null +++ b/tests/test_common/error_utils.py @@ -0,0 +1,82 @@ +import os + +ERROR_KEYWORDS = [ + "RuntimeError", + "out of memory", + "ValueError", + "FileNotFoundError", + "ConnectionRefusedError", + "ClientConnectorError", + "CancelledError", + "TimeoutError", + "PMI2_Init failed to initialize", + "OSError", +] +SLURM_LOG_TAIL_LINES = 200 # Number of lines to print from slurm job logs +ERROR_CONTEXT_LINES = 100 # Number of lines to print before and after error line + + +def check_error(file_path: str) -> list[tuple[int, str]]: + if not os.path.exists(file_path): + return [] + + error_lines = [] + with open(file_path, "r", errors="replace") as f: + for line_idx, line in enumerate(f, start=1): + for keyword in ERROR_KEYWORDS: + if keyword in line: + error_lines.append((line_idx, line.strip())) + break # Only add line once even if multiple keywords match + + return error_lines + + +def report_error( + error_msg: str | Exception, log_files: list[str], tail_lines: int = SLURM_LOG_TAIL_LINES +) -> None: + # Convert Exception to string if needed + if isinstance(error_msg, Exception): + error_msg_str = str(error_msg) + else: + error_msg_str = error_msg + + messages = [error_msg_str] + + for log_file in log_files: + if not os.path.exists(log_file): + messages.append(f"Failed to read {log_file}: Path doesn't exist") + + all_lines = None + error_lines = [] + try: + with open(log_file, "r", errors="replace") as f: + all_lines = f.readlines() + for line_idx, line in enumerate(f, start=1): + for keyword in ERROR_KEYWORDS: + if keyword in line: + error_lines.append((line_idx, line.strip())) + break + except Exception as e: + all_lines = None + error_lines = [] + messages.append(f"Failed to read {log_file}: {e}") + + if error_lines: + error_lines_str = ", ".join( + [f"Error line {line_idx}: {line_str}" for line_idx, line_str in error_lines] + ) + messages.append(error_lines_str) + # Find the first error line number for context + first_idx = min(line_idx for line_idx, _ in error_lines) + if all_lines is not None: + # Use all_lines for error context + start_idx = max(0, first_idx - ERROR_CONTEXT_LINES - 1) + end_idx = min(len(all_lines), first_idx + ERROR_CONTEXT_LINES) + context_lines = all_lines[start_idx:end_idx] + messages.append("".join(context_lines)) + else: + tail_content = "".join(all_lines[-tail_lines:]) if all_lines else "(empty)" + messages.append(f"--- {log_file} [last {tail_lines} lines] ---") + messages.append(tail_content) + + raise RuntimeError("\n".join(messages)) diff --git a/tests/test_common/http_utils.py b/tests/test_common/http_utils.py index 07826751b74f..9628dff1809f 100644 --- a/tests/test_common/http_utils.py +++ b/tests/test_common/http_utils.py @@ -3,16 +3,37 @@ import requests +from test_common.error_utils import check_error -def wait_for_endpoint_ready(url: str, timeout: int = 300, server_proc: subprocess.Popen = None): + +def wait_for_endpoint_ready( + url: str, + timeout: int = 300, + check_files: list[str] | None = None, + server_proc: subprocess.Popen | None = None, +): start = time.monotonic() + iteration = 0 while time.monotonic() - start < timeout: + # Check server_proc if provided (singular) if server_proc is not None: exit_code = server_proc.poll() if exit_code is not None: raise RuntimeError( f"Server process exited with code {exit_code} before becoming ready." ) + + iteration += 1 + if check_files and iteration % 300 == 0: + for check_file in check_files: + error_lines = check_error(check_file) + if error_lines: + error_lines_str = ", ".join( + [f"line {line_idx}: {line_str}" for line_idx, line_str in error_lines] + ) + raise RuntimeError( + f"Found error in server file {check_file}: {error_lines_str}" + ) try: time.sleep(1) if requests.get(url, timeout=5).status_code == 200: