Repository navigation
[None][feat] cache transceiver test in Perf sanity #16674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
chuangz0
merged 21 commits into
NVIDIA:main
from
chuangz0:perf_sanity_cache_transceiver_test
Jul 29, 2026
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
f0e0920
[None][test] Add cache transceiver precheck driver for disagg perf sa…
chuangz0 05323f9
[None][infra] Gate disagg perf sanity stages on a cache transceiver p…
chuangz0 c98289d
[None][infra] Print the test-results artifact URL when a Slurm stage …
chuangz0 94a522c
[None][test] Drop pickle from the precheck ZMQ control channel
chuangz0 b870a9f
[None][test] Support KVCacheManagerV2 in the cache transceiver precheck
chuangz0 7099f81
[None][test] Guard the precheck rendezvous against stale files from r…
chuangz0 723125e
[None][test] Keep ctx precheck instances alive until the gen finishes…
chuangz0 73928d1
[None][test] Add stall-debugging logs to the precheck driver
chuangz0 ea597c0
[None][test] Budget NIXL agent wire-up in the precheck's first rep
chuangz0 60bf16e
[None][test] Simplify the precheck: one owner per policy, leaner hot …
chuangz0 5c5f778
[None][test] Readability pass on the precheck driver
chuangz0 760d8e1
[None][test] Stop capturing NIXL_* env in precheck verdicts
chuangz0 de67ddd
[None][test] Run the network check on unmodelable models via a simpli…
chuangz0 0c3b7d9
[None][test] Rename the precheck's 'chunk' concept to 'wave'
chuangz0 88e134b
[None][test] Fail-fast the cache-transceiver precheck and fix review …
chuangz0 a1dd9c9
[None][test] Fix pre-commit lint findings across the precheck code
chuangz0 12ffec3
[None][infra] Print the exact test-results artifact URL on Slurm failure
chuangz0 8af0ac8
[None][fix] Address review: MTP depth fallback, abort-flag cleanup an…
chuangz0 14d0a67
[None][test] Add unit, contract and single-GPU e2e coverage for the c…
chuangz0 222c21a
[None][fix] Parse the renamed transceiver perf CSVs in the harness an…
chuangz0 427b1ab
[None][fix] Track the V2 resolver's new signature and disagg gating i…
chuangz0 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
180 changes: 180 additions & 0 deletions
180
jenkins/scripts/perf/disaggregated/slurm_ct_precheck_gate.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,180 @@ | ||
| # Cache-transceiver precheck gate for the disaggregated perf-sanity launch | ||
| # script. submit.py splices this file into the generated launch script ahead | ||
| # of slurm_launch_draft.sh, which calls run_cache_transceiver_precheck after | ||
| # computing the per-server node slices. Kept as functions in a separate file | ||
| # so the gate logic can be sourced and exercised standalone. | ||
| # | ||
| # Expects the launch-script globals: srunArgs, numGenServers, numCtxServers, | ||
| # nodesPerGenServer/nodesPerCtxServer, gpusPerNodePerGenServer/ | ||
| # gpusPerNodePerCtxServer, genNodeLists/ctxNodeLists, testOutputDir, | ||
| # jobWorkspace, pytestCommandCTXPrecheck/pytestCommandGENPrecheck, | ||
| # precheckRunScript, ctPrecheckEnabled, ctPrecheckTimeout, stageName, | ||
| # and the cleanup_on_failure function. | ||
|
|
||
| # Escape text for embedding in XML; junit parsers also choke on raw control | ||
| # bytes that MPI/UCX logs may contain, so strip those too. | ||
| ct_xml_escape() { | ||
| sed -e 's/&/\&/g' -e 's/</\</g' -e 's/>/\>/g' -e 's/"/\"/g' \ | ||
| | tr -d '\000-\010\013\014\016-\037' | ||
| } | ||
|
|
||
| # First few root-cause-shaped lines of a step log — the tail alone can miss | ||
| # the real error when it happened early and retry spam follows. | ||
| ct_first_errors() { | ||
| grep -m 5 -nE "Traceback \(most recent call last\)|MPI_ABORT|MPIR_Err|srun: error|Segmentation fault|CUDA error|RuntimeError|AssertionError|INIT_ERROR|TRANSFER_ERROR" \ | ||
| "$1" 2>/dev/null || true | ||
| } | ||
|
|
||
| # Shared verdict predicate + failing-log excerpt, so the console summary and | ||
| # the junit xml cannot drift apart. | ||
| ct_step_passed() { | ||
| local statusFile="$precheckDir/status/$1.status" | ||
| [ -f "$statusFile" ] && grep -q "^PASS" "$statusFile" | ||
| } | ||
|
|
||
| ct_step_excerpt() { | ||
| local stepLog="$precheckDir/logs/$1.log" | ||
| echo "First error lines (line-numbered):" | ||
| ct_first_errors "$stepLog" | ||
| echo "Log tail ($stepLog):" | ||
| tail -n 60 "$stepLog" 2>/dev/null || true | ||
| } | ||
|
|
||
| # Console summary for a failed precheck: per-instance verdicts, first error | ||
| # lines + tail of each failing step log, and UCX red-flag lines. | ||
| # Uses: precheckDir, precheckNames. | ||
| ct_print_failure_summary() { | ||
| echo "====================================================================" | ||
| echo "CACHE TRANSCEIVER PRECHECK FAILED - the disaggregated test will NOT run" | ||
| echo "Instance verdicts:" | ||
| cat "$precheckDir"/status/*.status 2>/dev/null \ | ||
| || echo "(no status files - steps died before transceiver setup; see logs below)" | ||
| echo "" | ||
| echo "Failing step logs:" | ||
| for k in "${!precheckNames[@]}"; do | ||
| ct_step_passed "${precheckNames[$k]}" && continue | ||
| echo "----- ${precheckNames[$k]} -----" | ||
| ct_step_excerpt "${precheckNames[$k]}" | ||
| done | ||
| echo "" | ||
| echo "UCX red flags (host-staged tcp fallback / UCX errors), if any:" | ||
| grep -hE "sw-emul|UCX +(ERROR|WARN)" "$precheckDir"/logs/*.log 2>/dev/null | sort -u | head -20 || true | ||
| echo "Full artifacts: $precheckDir (status/*.json, logs/, csv/)" | ||
| echo "====================================================================" | ||
| } | ||
|
|
||
| # Synthetic junit result so the failure shows up as a test entry in the | ||
| # Jenkins test report: uploadResults scps $jobWorkspace/results*.xml back and | ||
| # junit() ingests them. Best-effort — callers must not let this mask the real | ||
| # failure path. Uses: precheckDir, precheckNames, jobWorkspace, stageName. | ||
| ct_write_junit_xml() { | ||
| local junitXml="$jobWorkspace/results-ct-precheck.xml" | ||
| local suiteName | ||
| suiteName="$(printf '%s' "${stageName:-${SLURM_JOB_NAME:-disagg_perf_sanity}}" | ct_xml_escape)" | ||
| local junitFailures=0 | ||
| local junitCases="" | ||
| local name verdict detail | ||
| for k in "${!precheckNames[@]}"; do | ||
| name="${precheckNames[$k]}" | ||
| if ct_step_passed "$name"; then | ||
| junitCases+="<testcase name=\"cache_transceiver_precheck[$name]\" classname=\"$suiteName\" time=\"0\"/>"$'\n' | ||
| continue | ||
| fi | ||
| junitFailures=$((junitFailures + 1)) | ||
| verdict="$( (head -n 1 "$precheckDir/status/$name.status" 2>/dev/null \ | ||
| || echo "NO_STATUS: step died before writing a verdict (see log)") | ct_xml_escape)" | ||
| detail="$(ct_step_excerpt "$name" | ct_xml_escape)" | ||
| junitCases+="<testcase name=\"cache_transceiver_precheck[$name]\" classname=\"$suiteName\" time=\"0\">" | ||
| junitCases+="<failure message=\"$verdict\">$detail</failure></testcase>"$'\n' | ||
| done | ||
| if { | ||
| echo '<?xml version="1.0" encoding="UTF-8"?>' | ||
| echo "<testsuites><testsuite name=\"$suiteName\" tests=\"${#precheckNames[@]}\" failures=\"$junitFailures\" errors=\"0\" skipped=\"0\" time=\"0\">" | ||
| printf '%s' "$junitCases" | ||
| echo "</testsuite></testsuites>" | ||
| } > "$junitXml" 2>/dev/null; then | ||
| echo "Synthetic junit result written to $junitXml (will appear in the Jenkins test report)" | ||
| else | ||
| echo "WARNING: could not write synthetic junit xml to $junitXml (non-fatal)" | ||
| fi | ||
| } | ||
|
|
||
| # Run one precheck srun per ctx/gen server instance with the same node | ||
| # slices, MPI topology, and UCX env as the real server steps | ||
| # (pytestCommand{CTX,GEN}Precheck embed the same ucx_tls_cmd + worker env var | ||
| # strings). On failure: console summary + synthetic junit, then the stage | ||
| # aborts via cleanup_on_failure — before any model bring-up. | ||
| run_cache_transceiver_precheck() { | ||
| if [ "${ctPrecheckEnabled:-0}" != "1" ] || [ "${TRTLLM_DISAGG_BENCHMARK_GEN_ONLY:-0}" = "1" ]; then | ||
| return 0 | ||
| fi | ||
| echo "Starting cache transceiver precheck..." | ||
| precheckDir="$testOutputDir/cache_transceiver_precheck" | ||
| mkdir -p "$precheckDir/logs" | ||
| # A reused work dir (Slurm requeue reruns this batch script with the same | ||
| # directories) may hold a previous run's rendezvous/status/csv/abort files: | ||
| # stale addr files would point gen leaders at dead ports, stale status files | ||
| # would pollute the verdict aggregation below, a stale precheck.abort would | ||
| # fail-fast-skip the whole rerun (a requeued job keeps its SLURM_JOB_ID, so | ||
| # the driver's job-id stamp cannot tell it apart), and stale bandwidth CSVs | ||
| # (the Python transceiver's perf_<uuid>_<rank>.csv are per-run and appended) | ||
| # would make parse_python_bandwidth_gbps median over two runs' samples. The | ||
| # driver also job-id-stamps addr files as a second line of defense. | ||
| rm -f "$precheckDir"/rendezvous/*.addr "$precheckDir"/status/*.status \ | ||
| "$precheckDir"/status/*.json "$precheckDir"/precheck.abort 2>/dev/null || true | ||
| rm -rf "$precheckDir"/csv 2>/dev/null || true | ||
| precheckPids=() | ||
| precheckNames=() | ||
| # ct_launch_step <role> <idx> <nodes> <gpusPerNode> <nodeList> <pytestCmd> | ||
| ct_launch_step() { | ||
| local role=$1 i=$2 nodes=$3 gpusPerNode=$4 nodeList=$5 pytestCmd=$6 | ||
| export DISAGG_SERVING_TYPE="${role^^}_PRECHECK_$i" | ||
| export pytestCommand="$pytestCmd --server-idx $i" | ||
| timeout -k 60 "${ctPrecheckTimeout:-900}" \ | ||
| srun "${srunArgs[@]}" --mpi=pmix --kill-on-bad-exit=1 \ | ||
| -N "$nodes" \ | ||
| -w "$nodeList" \ | ||
| --ntasks=$((nodes * gpusPerNode)) \ | ||
| --ntasks-per-node="$gpusPerNode" \ | ||
| bash $precheckRunScript &> "$precheckDir/logs/${role}_$i.log" & | ||
| precheckPids+=($!) | ||
| precheckNames+=("${role}_$i") | ||
| sleep 5 # Wait for pyxis container namespace initialization to avoid race condition | ||
| } | ||
| local i | ||
| for i in $(seq 0 $((numGenServers - 1))); do | ||
| ct_launch_step gen "$i" "$nodesPerGenServer" "$gpusPerNodePerGenServer" \ | ||
| "${genNodeLists[$i]}" "$pytestCommandGENPrecheck" | ||
| done | ||
| for i in $(seq 0 $((numCtxServers - 1))); do | ||
| ct_launch_step ctx "$i" "$nodesPerCtxServer" "$gpusPerNodePerCtxServer" \ | ||
| "${ctxNodeLists[$i]}" "$pytestCommandCTXPrecheck" | ||
| done | ||
|
|
||
| local precheckFailed=0 k rc | ||
| for k in "${!precheckPids[@]}"; do | ||
| if wait "${precheckPids[$k]}"; then | ||
| echo "Precheck step ${precheckNames[$k]} passed" | ||
| else | ||
| rc=$? | ||
| echo "Precheck step ${precheckNames[$k]} FAILED (exit $rc; 124 = external timeout)" | ||
| precheckFailed=1 | ||
| fi | ||
| done | ||
|
|
||
| if [ "$precheckFailed" -eq 1 ]; then | ||
| ct_print_failure_summary | ||
| ct_write_junit_xml | ||
| cleanup_on_failure "Cache transceiver precheck failed. See summary above and $precheckDir" | ||
| fi | ||
| # No status files means every step took the skip path (e.g. the yaml has no | ||
| # cache_transceiver_config.backend): the run wrote no verdicts, so report it | ||
| # as SKIPPED rather than an empty "PASSED" that reads like real validation. | ||
| if ls "$precheckDir"/status/*.status >/dev/null 2>&1; then | ||
| echo "Cache transceiver precheck PASSED:" | ||
| cat "$precheckDir"/status/*.status 2>/dev/null || true | ||
| else | ||
| echo "Cache transceiver precheck SKIPPED: not applicable for this config" \ | ||
| "(no verdicts written; see $precheckDir/logs)" | ||
| fi | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| #!/bin/bash | ||
|
|
||
| # Per-rank container entrypoint for the disagg cache-transceiver PRECHECK | ||
| # step (launched by slurm_launch_draft.sh BEFORE the real ctx/gen servers). | ||
| # | ||
| # It intentionally mirrors slurm_run.sh's runtime environment: the same | ||
| # slurm_env_setup.sh is sourced (LD_LIBRARY_PATH, the `unset UCX_TLS=tcp` | ||
| # fixup, PMIX_MCA_gds), and $pytestCommand carries the same | ||
| # `unset/export UCX_TLS ...` prefix and worker env vars as the real ctx/gen | ||
| # worker steps (built from the same strings by jenkins/scripts/perf/submit.py), | ||
| # so a precheck PASS/FAIL is representative of the network environment the | ||
| # real test will run in. Unlike slurm_run.sh it skips coverage/perf-report | ||
| # handling -- the precheck is a plain MPI program, not a pytest run. | ||
|
|
||
| set -xEeuo pipefail | ||
| trap 'rc=$?; echo "Error in file ${BASH_SOURCE[0]} on line $LINENO: $BASH_COMMAND (exit $rc)"; exit $rc' ERR | ||
|
|
||
| # CI (jenkins/L0_Test.groovy) exports resourcePathNode with the /tmp | ||
| # extraction layout; the local flow (jenkins/scripts/perf/local/submit.py) | ||
| # exports llmSrcNode pointing at the repo directly and has no | ||
| # resourcePathNode. Honor whichever layout is present. | ||
| if [ -n "${resourcePathNode:-}" ]; then | ||
| cd "$resourcePathNode" | ||
| llmSrcNode=$resourcePathNode/TensorRT-LLM/src | ||
| fi | ||
| : "${llmSrcNode:?either resourcePathNode or llmSrcNode must be exported}" | ||
|
|
||
| source "$llmSrcNode/jenkins/scripts/slurm_env_setup.sh" | ||
| slurm_setup_runtime_env | ||
|
|
||
| echo "Precheck rank ${SLURM_PROCID:-?} (${DISAGG_SERVING_TYPE:-unknown}) command: $pytestCommand" | ||
|
|
||
| set +e | ||
| eval $pytestCommand | ||
| precheck_exit_code=$? | ||
| set -e | ||
|
|
||
| echo "Rank${SLURM_PROCID:-?} cache-transceiver precheck finished with exit code $precheck_exit_code" | ||
| exit $precheck_exit_code |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.