Skip to content

[NV][AgentX] Add glm5.1-fp8-b200-tilert-agentic (TileRT PD disagg) / [NV][AgentX] 新增 glm5.1-fp8-b200-tilert-agentic(TileRT PD 分离) - #2650

Open
Oseltamivir wants to merge 1 commit into
mainfrom
agent/internalize-pr-2645
Open

[NV][AgentX] Add glm5.1-fp8-b200-tilert-agentic (TileRT PD disagg) / [NV][AgentX] 新增 glm5.1-fp8-b200-tilert-agentic(TileRT PD 分离)#2650
Oseltamivir wants to merge 1 commit into
mainfrom
agent/internalize-pr-2645

Conversation

@Oseltamivir

@Oseltamivir Oseltamivir commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Attribution / 作者署名

This internal PR reproduces #2645 from the repository branch agent/internalize-pr-2645 because the original head branch is hosted in a fork.

All implementation credit belongs to the original PR author, @CrimsonDump (XieBaijie). The imported commit preserves CrimsonDump as its author.

本内部 PR 从仓库内分支 agent/internalize-pr-2645 复现 #2645,因为原 PR 的 head 分支位于 fork 中。

全部实现贡献归原 PR 作者 @CrimsonDump(XieBaijie)所有;导入后的 commit 保留 CrimsonDump 为作者。

Description

Add the GLM-5.1-FP8 B200 AgentX (agentic-coding) submission on TileRT PD disaggregation as one new master-config key and one new multi-node recipe.

  • glm5.1-fp8-b200-tilert-agentic: vLLM prefill + TileRT decode, 1P1D with TP8 on each side and NIXL KV transfer.
  • Use the existing cluster:b200-dgxc runner label.
  • Keep the single concurrency point [1].
  • Route agentic configs to benchmarks/multi_node/agentic/ through SCENARIO_SUBDIR.
  • Add AIPerf trace replay under LOGS/agentic/conc_<N>/ and accept the Hugging Face repository ID as a served model name.
  • Install the internal 0.1.5.post2+inferencex.1 wheel and wait up to 1,800 seconds for the single decode node instead of returning HTTP 429 immediately.

中文说明

新增 GLM-5.1-FP8 B200 AgentX(agentic-coding)在 TileRT PD 分离上的提交,包含一个新的主配置键和一个新的多节点配方。

  • glm5.1-fp8-b200-tilert-agentic:vLLM prefill + TileRT decode,1P1D、两侧各 TP8,KV 通过 NIXL 传输。
  • 使用现有的 cluster:b200-dgxc runner label。
  • 保持单一并发点 [1]
  • 通过 SCENARIO_SUBDIR 将 agentic 配置路由到 benchmarks/multi_node/agentic/
  • LOGS/agentic/conc_<N>/ 下新增 AIPerf trace replay,并接受 Hugging Face repository ID 作为 served model name。
  • 安装内部 0.1.5.post2+inferencex.1 wheel;单个 decode node 忙时最多等待 1,800 秒,不再立即返回 HTTP 429。

Internal wheel / 内部 wheel

The public TileRT repository cannot build the native wheel and upstream post3 is unavailable. This PR therefore preserves the official post2 native libraries and patches only tilert/pd_vllm/pd_router.py.

TileRT 公共仓库无法构建 native wheel,且上游 post3 不可获取。因此,本 PR 保留官方 post2 native library,仅修改 tilert/pd_vllm/pd_router.py

Validation / 验证

  • Python 3.12 rebuilt the wheel successfully; archive, RECORD, metadata, local version, and patched-router parity checks passed.

  • Threaded tests covered immediate acquisition, bounded waiting, release notification, timeout, and async event-loop offload.

  • Anonymous download through the exact launcher URL reproduced the pinned SHA256.

  • YAML parsing and Bash syntax passed for all touched files.

  • Exact-key generation produced one AgentX job on cluster:b200-dgxc, concurrency [1], router 0.1.5.post2+inferencex.1.

  • validate_perf_changelog.py passed against current origin/main with additions only.

  • pytest utils/matrix_logic/: 231 passed.

  • Run 32164342913 established the post2 failure mode: 3 of 27 profiling requests received HTTP 429 (all decode nodes busy), exceeding AIPerf's 10% threshold. The replacement run validates this backport.

  • Python 3.12 成功重建 wheel;archive、RECORD、metadata、local version 与 patched-router parity 检查均通过。

  • 线程测试覆盖立即获取、有界等待、release notification、timeout 与 async event-loop offload。

  • 通过 launcher 使用的精确 URL 匿名下载,得到固定 SHA256。

  • 所有修改文件的 YAML 解析和 Bash 语法检查通过。

  • 精确配置生成得到一个 AgentX job:cluster:b200-dgxc、并发 [1]、router 0.1.5.post2+inferencex.1

  • validate_perf_changelog.py 对当前 origin/main 校验通过,仅有新增内容。

  • pytest utils/matrix_logic/:231 项通过。

  • Run 32164342913 证明了 post2 的失败模式:27 个 profiling request 中 3 个收到 HTTP 429(all decode nodes busy),超过 AIPerf 10% 阈值。replacement run 将验证本 backport。

Remaining observation / 剩余观察项

TileRT does not expose router/decode Prometheus metrics, and GLM-5.1's 202752-position context limit leaves 175 of 393 traces eligible.

TileRT 未暴露 router/decode Prometheus metrics;GLM-5.1 的 202752-position context limit 使 393 条 trace 中有 175 条符合条件。

@github-actions

Copy link
Copy Markdown
Contributor

Thanks for the contribution! Please reach out to respective companies' CODEOWNER to fill in the latest PR_REVIEW_CHECKLIST.md before pinging core maintainer on Slack for review. In order for the signoff PR check bot to trigger, you must follow the PR_REVIEW_CHECKLIST.md template correctly, including the phrase As a PR reviewer and CODEOWNER, I have reviewed this and have.

For PR verification, add the full-sweep-fail-fast label (strongly recommended) to this PR — the benchmark sweep only runs on labeled PRs. Use full-sweep-enabled only if you need matrix jobs to keep running past a failure.

PR authors are responsible for ensuring that after merging, all GitHub Action jobs fully pass. A lot of the time, failures are just flakes and simply re-running the failed jobs will fix it. See GitHub's docs on re-running failed jobs


感谢你的贡献!请联系相应公司的 CODEOWNER 填写最新的 PR_REVIEW_CHECKLIST.md,然后再在 Slack 上联系核心维护者进行审阅。为了触发 signoff PR 检查机器人,你必须正确遵循 PR_REVIEW_CHECKLIST.md 模板,包括保留英文语句 As a PR reviewer and CODEOWNER, I have reviewed this and have

如需进行 PR 验证,请为此 PR 添加 full-sweep-fail-fast 标签(强烈推荐)— 基准测试 sweep 仅在带有标签的 PR 上运行。仅当需要矩阵任务在失败后继续运行时才使用 full-sweep-enabled

PR 作者有责任确保合并后所有 GitHub Action 任务完全通过。 很多时候失败只是偶发抖动(flake),重新运行失败的任务即可解决。参见 GitHub 关于重新运行失败任务的文档

@Oseltamivir
Oseltamivir force-pushed the agent/internalize-pr-2645 branch from 89289b1 to a344d06 Compare August 18, 2026 16:16
@Oseltamivir
Oseltamivir marked this pull request as ready for review August 18, 2026 16:31
@Oseltamivir
Oseltamivir requested a review from a team August 18, 2026 16:31
@claude

claude Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Oseltamivir's task in 14m 25s —— View job


PR Review — glm5.1-fp8-b200-tilert-agentic (TileRT PD disagg)

  • Gather context (diff vs origin/main, AGENTS.md)
  • Review new benchmark recipe benchmarks/multi_node/agentic/glm5.1_fp8_b200_tilert-disagg.sh
  • Review benchmarks/multi_node/tilert_utils/run_node.sh changes
  • Review config changes (nvidia-master.yaml, runners.yaml, launcher)
  • Validate perf-changelog rules (appended at end, master-config pairing)
  • Check image accessibility / enroot import / script style rules
  • Post inline comments and summary

Summary

No blocking issues found. Two 🟡 warnings posted inline:

  1. run_node.sh:296-300run_agentic_replay_and_write_outputs (benchmark_lib.sh) leaks set -e back into run_node.sh, so a failed replay aborts the script before touch "$DONE_SENTINEL", skipping the decode node's graceful shutdown (it then gets force-killed by submit.sh after the drain timeout). The job still fails correctly; the fix is a one-line guard.
  2. perf-changelog.yaml — the entry lists only the new agentic key, but the PR also changes the existing glm5.1-fp8-b200-tilert runtime (TileRT 0.1.5.post2post3 default in setup_deps.sh, master-config router version bump, and pd_router now always receives --queue-timeout 0). That existing curve won't be re-swept, leaving its published results on post2 while the config claims post3.

Everything else checked out: changelog entry is appended at the physical tail with the master-config edit paired; images are public (ghcr.io/tile-ai/tilert:0.1.5, vllm/vllm-openai:v0.26.0); submit.sh retains the enroot import docker:// pattern; the SCENARIO_SUBDIR == "agentic/" launcher gate matches the workflow's value exactly; IS_AGENTIC/SCENARIO_TYPE reach run_node.sh via workflow env + srun --export=ALL; the resolve_trace_sourceinstall_agentic_deps order is safe (ensure_hf_cli self-installs deps) and matches agentic_srt.sh; multinode agentic matrix generation defaults kv-offloading to none so require_agentic_kv_offload_none passes, and the missing hardware: entry for cluster:b200-dgxc-slurm is only consulted on the dram path; glm5.1/fp8 is already mapped in launch_b200-dgxc.sh; the _conc<N> result naming matches the workflow's ${RESULT_FILENAME}_conc*.json check; and the new recipe mirrors the existing fixed-seq-len TileRT recipe with only the expected agentic deltas.

Comment on lines +296 to +300
if [[ "$TILERT_IS_AGENTIC" == "1" ]]; then
run_agentic_replay; BENCH_RC=$?
else
run_bench_and_eval; BENCH_RC=$?
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING: On a failed replay, the script aborts here before touch "$DONE_SENTINEL" because of a leaked set -e.

Why it matters: run_agentic_replay_and_write_outputs (benchmark_lib.sh:2194–2214) toggles set +e/set -e and returns with errexit left enabled. run_node.sh does not run under set -e and its shutdown contract relies on always reaching touch "$DONE_SENTINEL" (line 301) so the decode node exits gracefully. Inside run_agentic_replay, the failing call is caught by || { rc=$?; ... }, but per bash semantics the leaked set -e takes effect once that AND-OR list completes — so return $rc with a nonzero rc makes the plain call run_agentic_replay; BENCH_RC=$? exit the whole script immediately. The sentinel is never touched, the decode node never sees the shutdown signal, and submit.sh only force-kills the decode srun after the TILERT_DECODE_DRAIN timeout. The non-agentic path is unaffected (nothing on it enables errexit), so this is new behavior introduced with the agentic branch.

Fix: call the function in an AND-OR list (which suppresses errexit for the call) and restore the script's no-errexit state afterwards:

Suggested change
if [[ "$TILERT_IS_AGENTIC" == "1" ]]; then
run_agentic_replay; BENCH_RC=$?
else
run_bench_and_eval; BENCH_RC=$?
fi
if [[ "$TILERT_IS_AGENTIC" == "1" ]]; then
run_agentic_replay && BENCH_RC=0 || BENCH_RC=$?
{ set +e; } 2>/dev/null
else
run_bench_and_eval; BENCH_RC=$?
fi

Fix this →

Comment thread perf-changelog.yaml
Comment on lines +6079 to +6080
- config-keys:
- glm5.1-fp8-b200-tilert-agentic

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 WARNING: This PR also changes the runtime of the existing glm5.1-fp8-b200-tilert config, but the changelog entry only lists the new agentic key.

Why it matters: Three changes in this diff affect the existing fixed-seq-len config, not just the agentic one:

  1. benchmarks/multi_node/tilert_utils/setup_deps.sh bumps the default TILERT_VERSION from 0.1.5.post2 to 0.1.5.post3 (installed on both roles for every TileRT run);
  2. configs/nvidia-master.yaml bumps the existing key's router.version to 0.1.5.post3;
  3. run_node.sh now always passes --queue-timeout "$TILERT_QUEUE_TIMEOUT" (0 for non-agentic) to pd_router, a flag the old invocation never sent.

The post-merge sweep re-benchmarks only the keys listed in the appended changelog entry, so glm5.1-fp8-b200-tilert's published results will remain the 0.1.5.post2 numbers while its master-config entry claims 0.1.5.post3 — stale provenance for that curve.

Fix: add the existing key to this entry (with a description line for the TileRT pin bump and the new --queue-timeout 0 router flag), e.g.:

Suggested change
- config-keys:
- glm5.1-fp8-b200-tilert-agentic
- config-keys:
- glm5.1-fp8-b200-tilert-agentic
- glm5.1-fp8-b200-tilert

If the intent is that --queue-timeout 0 and post3 are behavior-identical for the fixed-seq-len path, that's still a dependency-version change to a published config and should be re-swept or explicitly documented.

fi
TILERT_QUEUE_TIMEOUT=${TILERT_QUEUE_TIMEOUT:-0}

AGENTIC_LOGS_DIR=${AGENTIC_LOGS_DIR:-$RESULT_DIR/LOGS/agentic}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 run_node.sh:36 defaults AGENTIC_LOGS_DIR to $RESULT_DIR/LOGS/agentic, and RESULT_DIR defaults to /workspace (the GITHUB_WORKSPACE bind-mount). run_agentic_replay() then mkdir -p's $AGENTIC_LOGS_DIR/conc_ for each concurrency point, creating new directories under /workspace, which violates the non-negotiable AGENTS.md invariant that benchmarks create no new directories there. Since the tilert container runs as root under enroot with no user remap, this can leave root-owned dirs in the shared runner checkout that block a later job's git checkout -- the fix is to default AGENTIC_LOGS_DIR outside /workspace, the same way the sibling benchmarks/multi_node/agentic_srt.sh defaults its result dir to /logs/agentic.

Extended reasoning...

The bug: run_node.sh line 36 sets AGENTIC_LOGS_DIR=${AGENTIC_LOGS_DIR:-$RESULT_DIR/LOGS/agentic}, and RESULT_DIR defaults to /workspace at line 8 (pre-existing). Neither variable is overridden anywhere else along the tilert launch chain (launch_b200-dgxc.sh -> the new glm5.1_fp8_b200_tilert-disagg.sh -> submit.sh -> run_node.sh), so by default AGENTIC_LOGS_DIR resolves to /workspace/LOGS/agentic.

Where it triggers: the new run_agentic_replay() function loops over CONC_LIST and does mkdir -p "$AGENTIC_LOGS_DIR/conc_${conc}" for every concurrency point. With this PR's config (conc-list: [1]), that is one call producing /workspace/LOGS/agentic/conc_1, but the code generalizes to any list. /workspace inside the container is bind-mounted from $GITHUB_WORKSPACE on the shared Slurm/enroot runner (per submit.sh's --container-mounts), i.e. it's the CI checkout directory, not a scratch dir.

Why nothing else prevents it: the pre-existing non-agentic path (run_bench_and_eval) only ever writes result files flat into RESULT_DIR via --result-dir; it never creates subdirectories, so this class of violation didn't exist in the tilert script before this PR. This is a genuinely new violation introduced here, not a latent pre-existing one.

Why it's forbidden: AGENTS.md line 24 states a non-negotiable benchmark invariant: 'Benchmarks create no new directories under /workspace. Root containers must not leave root-owned files in shared ... runner workspaces.' The tilert containers run under enroot with no user namespace remap (the existing convert_weights/TILERT_WEIGHTS_DIR logic in this same file is deliberately routed to /lustre/fsw/gharunners/... instead of /workspace for exactly this reason), so any directory this script creates under /workspace will be root-owned in the shared GITHUB_WORKSPACE checkout on the dgxc-slurm runner.

Impact: a root-owned /workspace/LOGS/agentic/conc_1 directory left behind after the job can block a subsequent job's git checkout/clean on the same shared runner checkout -- exactly the failure mode the invariant exists to prevent, and the same class of problem launch_b200-dgxc.sh already works around elsewhere (e.g. its NFS silly-rename cleanup loop, and routing model conversion outputs away from /workspace).

Proof (step-by-step):

  1. submit.sh mounts $GITHUB_WORKSPACE:/workspace into the container.
  2. run_node.sh runs with RESULT_DIR unset -> defaults to /workspace (line 8).
  3. Line 36: AGENTIC_LOGS_DIR unset -> defaults to /workspace/LOGS/agentic.
  4. For the new glm5.1-fp8-b200-tilert-agentic scenario, TILERT_ROLE=prefill calls run_agentic_replay().
  5. For conc=1 (the sole point in conc-list: [1]): conc_result_dir=/workspace/LOGS/agentic/conc_1; mkdir -p creates it, owned by root (container runs as root, no remap).
  6. This directory persists in the shared GITHUB_WORKSPACE checkout after the job exits, and a later job's checkout/clean on the same runner can fail against the root-owned tree.

The fix: mirror the sibling agentic recipe. benchmarks/multi_node/agentic_srt.sh:14 does BASE_RESULT_DIR=${RESULT_DIR:-/logs/agentic} -- outside /workspace -- precisely to avoid this. run_node.sh:36 should default AGENTIC_LOGS_DIR the same way, e.g. AGENTIC_LOGS_DIR=${AGENTIC_LOGS_DIR:-/logs/agentic} (or route it under the same out-of-workspace tree already used for TILERT_WEIGHTS_DIR), rather than nesting it under RESULT_DIR.

Comment on lines +245 to 262
run_agentic_replay() {
wait_for_server_ready --port "$ROUTER_PORT" \
--server-log "$BENCHMARK_LOGS_DIR/tilert_router.log" --server-pid "$ROUTER_PID"
local rc=0 conc conc_result_dir
local result_filename_base="$RESULT_FILENAME"
for conc in $CONC_LIST; do
conc_result_dir="$AGENTIC_LOGS_DIR/conc_${conc}"
mkdir -p "$conc_result_dir"
export CONC="$conc"
export RESULT_FILENAME="${result_filename_base}_conc${conc}"
build_replay_cmd "$conc_result_dir"
run_agentic_replay_and_write_outputs "$conc_result_dir" \
|| { rc=$?; echo "[agentic] WARNING: conc=$conc failed/timed out (rc=$rc)"; }
done
export RESULT_FILENAME="$result_filename_base"
return $rc
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 run_agentic_replay() in tilert_utils/run_node.sh:245-262 is a third copy of the same concurrency-loop scaffolding (loop CONC_LIST → mkdir conc_ → export CONC/RESULT_FILENAME → build_replay_cmd → run_agentic_replay_and_write_outputs) already duplicated in agentic_srt.sh and amd_utils/trace_replay.sh. The shared per-request primitives already live in benchmark_lib.sh, but this outer loop/naming contract does not, so a future change to it has to be hand-applied in three places.

Extended reasoning...

What: run_agentic_replay() (new in this PR, benchmarks/multi_node/tilert_utils/run_node.sh:245-262) loops over $CONC_LIST, creates a conc_<N> result directory, exports CONC/RESULT_FILENAME, and calls the shared build_replay_cmd + run_agentic_replay_and_write_outputs helpers. This is the third time this exact scaffolding is written out — benchmarks/multi_node/agentic_srt.sh (~lines 104-120) and benchmarks/multi_node/amd_utils/trace_replay.sh (~lines 130-155) both implement the identical loop/mkdir/export/call sequence around the same two benchmark_lib.sh primitives.

Code path: All three copies share the same contract: iterate CONC_LIST, create .../conc_${conc}, export CONC=$conc, set RESULT_FILENAME to a conc-suffixed name, call build_replay_cmd, then run_agentic_replay_and_write_outputs. build_replay_cmd (benchmark_lib.sh:1958) and run_agentic_replay_and_write_outputs (benchmark_lib.sh:2187) are already factored out as shared primitives, but the outer loop/directory/naming contract that wires them together is not — it lives independently in each of the three call sites.

Why existing code doesn't prevent it: benchmark_lib.sh already centralizes the per-request primitives, so there was an established place to add a shared wrapper; this PR instead adds a fresh copy inline in run_node.sh rather than extending or calling into a common helper. Nothing enforces that the three copies stay in sync — amd_utils/trace_replay.sh even carries a comment noting it must mirror agentic_srt.sh's contract by hand.

Impact: Low. The three copies currently agree on the conc_ directory + _conc filename suffix contract, and each has legitimate small variations (agentic_srt.sh does an idle-wait between points; amd_utils/trace_replay.sh clears KV caches between points). Nothing is broken today. But a future change to the per-conc directory/result-naming contract (e.g. adding a manifest file, changing the suffix format) would need to be hand-applied in three places, and a missed update would silently produce inconsistent result layouts across backends rather than fail loudly.

Suggested fix: Extract the common loop (iterate CONC_LIST, mkdir the per-conc dir, export CONC/RESULT_FILENAME, call build_replay_cmd, call run_agentic_replay_and_write_outputs, handle rc) into a shared helper in benchmark_lib.sh, parameterized by the two behavior hooks (idle-wait, cache-clear) via optional callback env vars or function names. Each of the three call sites would then just supply their environment and hooks.

Proof by construction: Diff the three implementations line-by-line: (1) run_node.sh:250-258 — for conc in $CONC_LIST; do conc_result_dir="$AGENTIC_LOGS_DIR/conc_${conc}"; mkdir -p ...; export CONC="$conc"; export RESULT_FILENAME="..."; build_replay_cmd ...; run_agentic_replay_and_write_outputs ...; done. (2) agentic_srt.sh ~104-120 — same shape, same five steps, plus one extra call to wait_for_agentic_servers_idle. (3) amd_utils/trace_replay.sh ~130-155 — same shape again, plus one extra call to clear_kv_caches. Removing the one extra line from each of (2) and (3) leaves three byte-for-byte identical loops — that identity is the DRY violation.

Comment on lines 138 to 145
export UCX_NET_DEVICES="${UCX_NET_DEVICES:-mlx5_0:1,mlx5_1:1,mlx5_2:1,mlx5_3:1,mlx5_4:1,mlx5_5:1,mlx5_6:1,mlx5_7:1}"
export UCX_MEMTYPE_CACHE="${UCX_MEMTYPE_CACHE:-n}"
export UCX_MEMTYPE_REG_WHOLE="${UCX_MEMTYPE_REG_WHOLE:-n}"
TILERT_DISAGG="$GITHUB_WORKSPACE/benchmarks/multi_node/${EXP_NAME%%_*}_${PRECISION}_b200_${FRAMEWORK}-disagg.sh"
TILERT_SUBDIR="multi_node"
[[ "${SCENARIO_SUBDIR}" == "agentic/" ]] && TILERT_SUBDIR="multi_node/agentic"
TILERT_DISAGG="$GITHUB_WORKSPACE/benchmarks/${TILERT_SUBDIR}/${EXP_NAME%%_*}_${PRECISION}_b200_${FRAMEWORK}-disagg.sh"
[[ -f "$TILERT_DISAGG" ]] || { echo "tilert disagg script not found: $TILERT_DISAGG"; exit 1; }
exec bash "$TILERT_DISAGG"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 sweep:AIPERF_MMAP_CACHE_HOST_PATH|HF_HUB_CACHE_HOST_PATH -- the tilert multinode IS_AGENTIC path never receives the shared aiperf/HF caches every other agentic recipe gets. Example: runners/launch_b200-dgxc.sh's tilert branch (line 145) execs into $TILERT_DISAGG and exits before the later 'if [[ "$IS_AGENTIC" == "1" ]]' block that mounts $AIPERF_MMAP_CACHE_HOST_PATH and $HF_HUB_CACHE_HOST_PATH; fix by also wiring those two into benchmarks/multi_node/tilert_utils/submit.sh's run_role() --container-mounts/--export so the tilert container gets /aiperf_mmap_cache and /hf_hub_cache with matching env vars, same as the srtctl and single-node paths.

Extended reasoning...

What the bug is

runners/launch_b200-dgxc.sh mounts and exports the two shared Lustre-backed caches — AIPERF_MMAP_CACHE_HOST_PATH (aiperf's content-addressed trace mmap cache) and HF_HUB_CACHE_HOST_PATH (the shared HF hub cache) — only in two places: the single-node srun --container-mounts=...,$AIPERF_MMAP_CACHE_HOST_PATH:/aiperf_mmap_cache branch near the bottom of the file, and the srtctl multinode if [[ "$IS_AGENTIC" == "1" ]] block that builds DEFAULT_MOUNTS_BLOCK and writes it into srtslurm.yaml's default_mounts.

The new glm5.1-fp8-b200-tilert-agentic scenario (added by this PR) goes through neither of those. It hits the IS_MULTINODE == "true" branch for FRAMEWORK == "tilert" at runners/launch_b200-dgxc.sh:138-145, which resolves $TILERT_DISAGG and does exec bash "$TILERT_DISAGG"; exit 1. exec replaces the current shell process, so control never reaches the later IS_AGENTIC block further down in the same script — that block is structurally unreachable for any tilert run, agentic or not.

Code path and why nothing else catches it

From there, TILERT_DISAGG (benchmarks/multi_node/agentic/glm5.1_fp8_b200_tilert-disagg.sh) execs into benchmarks/multi_node/tilert_utils/submit.sh, whose run_role() sets --container-mounts="$GITHUB_WORKSPACE:/workspace,$MODEL_PATH:$MODEL_PATH,$TILERT_WEIGHTS_DIR:$TILERT_WEIGHTS_DIR" and --export=ALL,TILERT_ROLE=...,DECODE_HOST=...,PREFILL_HOST=...,PORT=... — no aiperf cache mount, no HF hub cache mount, and neither AIPERF_DATASET_MMAP_CACHE_DIR nor HF_HUB_CACHE is exported. This PR's own run_node.sh changes add a TILERT_IS_AGENTIC prefill-side call to resolve_trace_source (which does hf download --repo-type dataset for cc-traces-weka-062126-256k, intending to land in the shared HF cache per its own comment) and build_replay_cmd (which builds aiperf's dataset mmap cache) — both landing in ephemeral, per-container default locations instead of the persistent mount every other agentic recipe uses.

Impact

Every job for this scenario re-downloads the multi-GB trace dataset and rebuilds AIPerf's mmap cache from scratch inside its enroot container, instead of reusing the Lustre-backed caches that both the single-node and srtctl-multinode agentic paths already share across jobs. The run still succeeds (the author's validation reports 539 requests, zero errors) — this is a persistent efficiency/reuse gap, not a correctness break.

Step-by-step proof

  1. Scenario glm5.1-fp8-b200-tilert-agentic sets FRAMEWORK=tilert, multinode: true, scenarios.agentic-coding → the launcher takes IS_MULTINODE=="true" and FRAMEWORK=="tilert".
  2. runners/launch_b200-dgxc.sh:145 runs exec bash "$TILERT_DISAGG" — process image replaced, script exits via the exec'd process's exit code; the IS_AGENTIC mount block later in the file is dead code for this path.
  3. submit.sh run_role()'s --container-mounts / --export (lines 55, 57) contain no reference to AIPERF_MMAP_CACHE_HOST_PATH, HF_HUB_CACHE_HOST_PATH, AIPERF_DATASET_MMAP_CACHE_DIR, or HF_HUB_CACHE.
  4. Inside the container, run_node.sh's prefill role calls resolve_trace_source and build_replay_cmd with those env vars unset, so both the dataset download and the mmap cache build go to ephemeral container-local storage, discarded when the job's enroot container is torn down.
  5. Next job run: cache miss again, full re-download and rebuild — unlike single-node and srtctl-multinode agentic runs, which persist both caches on Lustre.

Fix

Wire AIPERF_MMAP_CACHE_HOST_PATH and a shared HF_HUB_CACHE_HOST_PATH into tilert_utils/submit.sh's run_role() --container-mounts (as /aiperf_mmap_cache and /hf_hub_cache) and add AIPERF_DATASET_MMAP_CACHE_DIR=/aiperf_mmap_cache and HF_HUB_CACHE=/hf_hub_cache to its --export, mirroring what the srtctl DEFAULT_MOUNTS_BLOCK and the single-node srun invocation already do.

@Oseltamivir
Oseltamivir force-pushed the agent/internalize-pr-2645 branch from a344d06 to cd778c3 Compare August 18, 2026 16:50
@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor

@Oseltamivir
Oseltamivir force-pushed the agent/internalize-pr-2645 branch from cd778c3 to 809a733 Compare August 18, 2026 17:12
@github-actions

Copy link
Copy Markdown
Contributor

…a TileRT)

Ported from #2645. Original PR author: CrimsonDump (@CrimsonDump).

Build and pin an internal TileRT post2 queueing backport because upstream post3 is unavailable.

从 #2645 迁移。原 PR 作者:CrimsonDump(@CrimsonDump)。

由于上游 post3 不可获取,构建并固定内部 TileRT post2 排队 backport。

(cherry picked from commit 24d7457)
@Oseltamivir
Oseltamivir force-pushed the agent/internalize-pr-2645 branch from 809a733 to 5eb5760 Compare August 19, 2026 02:43
@github-actions

Copy link
Copy Markdown
Contributor

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants