Skip to content

[PowerX AMD] preserve telemetry through the measurement end / 保留完整窗口遥测 - #3041

Closed
edwingao28 wants to merge 2 commits into
mainfrom
fix/agentx-amd-power-window
Closed

[PowerX AMD] preserve telemetry through the measurement end / 保留完整窗口遥测#3041
edwingao28 wants to merge 2 commits into
mainfrom
fix/agentx-amd-power-window

Conversation

@edwingao28

@edwingao28 edwingao28 commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

Description

Superseded by #3026: AMD monitor fixes and validation travel together.

Keep AMD telemetry through the measurement end, handle delayed samples, bound cleanup, and retain invalid-boundary diagnostics.

Testing: 202 focused tests passed; delayed-sample regression failed before the fix. Bash/changelog checks passed.

Pending: MI355X hardware validation and the FIFO-startup review fix continue in #3026. No separate sweep is needed for this duplicate.

中文

中文说明

#3026 接替: AMD 监控修复与验证统一在该 PR 推进。

保留 AMD 遥测直到测量结束,处理延迟采样,限制清理等待,并保留无效边界行诊断。

测试: 202 项针对性测试通过;延迟采样回归测试在修复前失败。Bash/changelog 检查通过。

待完成: MI355X 硬件验证与 FIFO 启动问题的 review 修复继续在 #3026 完成。本重复范围无需单独运行 sweep。

Related Issue

Scope index and shared policy / 范围索引与共同规则: #3030.

Type of Change

  • Bug fix
  • New feature
  • Configuration change
  • Documentation update
  • Other (please describe)

Checklist

  • I have tested my changes locally
  • I have updated documentation if necessary
  • For every change that can affect benchmark performance and every recipe addition or modification, I have appended a new entry to the physical end of perf-changelog.yaml and have not edited historical entries
  • Before merging via reuse, an authorized maintainer (OWNER/MEMBER/COLLABORATOR) has commented /reuse-sweep-run on this PR. Do this only once there is a final full sweep that is all green with evals passing, since after this comment the sweep label will no longer automatically kick off new sweeps. Remove and re-add the label to force one.

Note

Medium Risk
Changes benchmark teardown timing and power validity rules for AMD AgentX runs; mis-tuned timeouts could delay stops or mark windows invalid, but cancellation remains bounded and failures stay explicit in audits.

Overview
Improves AMD GPU power telemetry so benchmark windows can be bracketed reliably and teardown noise does not corrupt validity.

Monitor lifecycle (benchmark_lib.sh): AMD amd-smi watch output now flows through a per-run FIFO with separate PIDs for the producer and awk consumer, so killing the parser does not leave amd-smi running or drop buffered rows. On stop, the fixed tail sleep is replaced by polling gpu_metrics.csv until every GPU has a usable tick (numeric epoch, power > 0) at or after the next whole second, bounded by AMD_MONITOR_STOP_TIMEOUT_S (default 30s). AgentX signal/EXIT cleanup sets that timeout to 0 so cancellation stays fast while normal completion still waits for coverage.

Aggregation (infx/results/power/single_node.py): Rows in the ingest band but outside the formal window with missing, non-finite, or ≤0 W power are skipped for bracketing and integration and counted in audit boundary_degenerate_rows (e.g. N/A or 0 W teardown tails no longer fake end bracketing). In-window invalid samples are unchanged.

Docs, perf-changelog.yaml, and shell/Python tests cover the new stop behavior, abort path, and degenerate-boundary semantics.

Reviewed by Cursor Bugbot for commit 942c058. Bugbot is set up for automated code reviews on this repo. Configure here.

保留 AMD 功耗测量边界及诊断信息。
@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 关于重新运行失败任务的文档

等待延迟到达的首条 AMD 有效遥测,并对不支持的采样流执行同一停止超时,避免提前结束采样或超时等待。
@edwingao28
edwingao28 marked this pull request as ready for review September 12, 2026 06:26
@edwingao28
edwingao28 requested a review from a team September 12, 2026 06:26
@claude

claude Bot commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Claude finished @edwingao28's task in 4m 1s —— View job


Review of PR #3041

  • Read the diff against origin/main
  • Review benchmarks/benchmark_lib.sh telemetry lifecycle changes
  • Review infx/results/power/single_node.py boundary handling
  • Run the touched test suites (blocked, see below)
  • Check perf-changelog.yaml entry position
  • Post findings

Summary

One 🟡 WARNING posted inline on benchmarks/benchmark_lib.sh:205-206: the new mkfifo ... || return 1 makes a monitor-setup failure abort the whole benchmark under the set -eo pipefail used by every AMD recipe, whereas before this PR monitor start was best-effort. A stale FIFO from a killed prior run in the reused workspace (same $$ suffix) or a result dir on a filesystem that rejects mknod would trigger it. The suggested fix removes any stale FIFO and degrades to no monitoring.

No blocking issues found. The FIFO reader/writer ordering, the trap re-entrancy during the coverage wait, the awk column detection (mirrors _detect_columns in single_node.py), and the boundary-degenerate row skip in the aggregator all look correct. The two perf-changelog.yaml entries are appended at the end of the file. No master config files were modified.

Not verified: the sandbox denied running pytest, bash -n, and py_compile, so I could not independently confirm the 201 passing tests claimed in the description. The MI355X hardware validation listed as pending in the description remains the real gate for the timing behaviour.

Comment on lines +205 to +206
GPU_MONITOR_PIPE="${output}.pipe.$$"
mkfifo "$GPU_MONITOR_PIPE" || return 1

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: mkfifo ... || return 1 turns a monitor-setup failure into a benchmark abort.

Why it matters: Every AMD recipe that calls start_gpu_monitor runs under set -eo pipefail (e.g. dsv4_fp8_mi300x.sh, dsv4_fp4_mi355x_vllm.sh), and the AgentX path at line 3454 is inside a set -e subshell. Before this PR, starting the monitor could never fail the run. Now mkfifo failing kills the benchmark before the server even launches, in two realistic cases:

  1. A stale FIFO at the same path. The default output is gpu_metrics.csv in the reused runner workspace, and the suffix is $$, which is easily reused across container runs. A prior run killed by a job cancel/timeout never reaches stop_gpu_monitor, so the FIFO stays behind and mkfifo returns EEXIST.
  2. The result dir living on a filesystem that rejects mknod (some network shares). The MI355X runner workspaces sit under /it-share/gharunners*.

Also, on this failure path GPU_MONITOR_VENDOR="amd" and GPU_MONITOR_PIPE stay set with no PIDs, so a later stop_gpu_monitor would still run the AMD teardown branch.

Fix: remove any stale FIFO first and degrade to "no monitoring" instead of failing, matching the pre-PR contract. Consider mktemp -u under ${TMPDIR:-/tmp} for the FIFO path if the result dir may be on a network share.

Suggested change
GPU_MONITOR_PIPE="${output}.pipe.$$"
mkfifo "$GPU_MONITOR_PIPE" || return 1
GPU_MONITOR_PIPE="${output}.pipe.$$"
rm -f "$GPU_MONITOR_PIPE"
if ! mkfifo "$GPU_MONITOR_PIPE" 2>/dev/null; then
echo "[GPU Monitor] Warning: mkfifo failed at $GPU_MONITOR_PIPE, skipping AMD monitoring" >&2
GPU_MONITOR_PIPE=""
GPU_MONITOR_VENDOR=""
return 0
fi

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 942c058. Configure here.

# Track both processes: killing only awk can leave amd-smi alive until
# its next write. Keep the FIFO beside this run's raw CSV, never shared.
GPU_MONITOR_PIPE="${output}.pipe.$$"
mkfifo "$GPU_MONITOR_PIPE" || return 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

mkfifo failure aborts AMD monitoring

Medium Severity

start_gpu_monitor now creates a named pipe beside the metrics CSV and return 1s if mkfifo fails. AgentX calls it without checking status, so under set -e a FIFO setup failure aborts the whole replay instead of skipping power. That is a new hard failure: the old anonymous pipe could not fail this way, and a missing SMI tool still returns 0.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 942c058. Configure here.

Comment on lines +296 to +331
# power > 0), or nothing when the stream holds no usable epoch-stamped row
# (e.g. an amd-smi build emitting ISO timestamps). Column detection mirrors
# _POWER_COL_RE/_POWER_EXCLUDE_RE/_GPU_INDEX_COL_RE in utils/aggregate_power.py.
# POSIX awk only: the ROCm container images ship mawk/busybox awk.
_amd_monitor_min_covered_tick() {
[[ -f "$GPU_METRICS_CSV" ]] || return 0
awk -F, '
NR == 1 {
for (i = 1; i <= NF; i++) {
name = tolower($i)
gsub(/^ +| +$/, "", name)
sub(/\r$/, "", name)
if (!power_col && name ~ /power/ && name !~ /limit|cap|max|min/)
power_col = i
if (!gpu_col && name ~ /^(index|gpu|gpu_id|gpu_index|card|device)$/)
gpu_col = i
}
next
}
!power_col || !gpu_col { next }
{
# amd-smi quotes list-valued cells that embed commas; neutralize
# them so the power cell keeps its header-relative position.
line = $0
sub(/\r$/, "", line)
if (line ~ /"/) {
n = split(line, seg, /"/)
line = ""
for (i = 1; i <= n; i++) {
if (i % 2 == 0) gsub(/,/, ";", seg[i])
line = line seg[i]
}
}
count = split(line, cell, /,/)
if (count < power_col || count < gpu_col) next
if (cell[1] !~ /^[0-9]+(\.[0-9]+)?$/) next

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.

🔴 _amd_monitor_min_covered_tick only treats column 1 as usable when it matches a plain numeric epoch (cell[1] !~ /^[0-9]+(\.[0-9]+)?$/ { next }). single_node.py's _parse_timestamp explicitly documents amd-smi emitting ISO-8601 timestamps 'as observed in practice', which this regex rejects on every row. For such builds the poll never finds a covered tick, so _wait_for_amd_stop_coverage silently blocks the full AMD_MONITOR_STOP_TIMEOUT_S (30s default) on every stop instead of the old ~3-5s fixed sleep, adding ~25s teardown latency per benchmark run. Fix: parse ISO-8601 (and other formats single_node.py tolerates) in the coverage awk too, or detect an all-non-numeric stream quickly and stop waiting instead of running to the full timeout.

Extended reasoning...

amd-smi (a version/config producing ISO timestamps, per single_node.py's own comment 'amd-smi: ISO 8601 ... or epoch seconds') writes rows whose first column is e.g. '2025-01-15T12:34:56.789'. In _amd_monitor_min_covered_tick, cell[1] !~ /^[0-9]+(\.[0-9]+)?$/ is true for every such row, so next skips it; newest[] stays empty and the function prints nothing. _wait_for_amd_stop_coverage's covered is always empty, so the -ge target check never passes; the loop runs sleep 1 until date +%s -ge deadline (30s after entry by default), then logs 'never covered the stop request' and returns. Every AMD stop_gpu_monitor call on such a build now pays ~30s versus the previous unconditional sleep $((interval+2)) (~3-5s), a real per-run latency regression the comment anticipates but does not size.

Verification: nit — acknowledged in diff (note's claims hold). Mechanism is real: benchmark_lib.sh:331 if (cell[1] !~ /^[0-9]+(\.[0-9]+)?$/) next rejects ISO-8601 first columns (2025-01-15T12:34:56.789) on every row, so newest[] stays empty and _amd_monitor_min_covered_tick prints nothing. In _wait_for_amd_stop_coverage, covered is then always empty, the `[[ -n "$covered" && "$covered" -ge…

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

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant