Skip to content

Commit dc73590

Browse files
committed
fix: do not hijack a developer's own GPU debugging session
mfc.sh test and mfc.sh bench are developer commands, not only CI entry points, and the agent was enabled purely on the library being reachable -- so it switched on for local runs on any ROCm machine. mfc.sh run is untouched and unaffected. Two ways that was wrong, both silent. Setting HSA_TOOLS_LIB behind someone collecting a GPU core dump gives them "Failed to enable debug interface" and no dump, because the agent and ROCr core dumps are mutually exclusive -- the same path an attached rocgdb trips. And the OFFLOAD_TRACK_* values overwrote whatever the caller had chosen. An explicit setting is now authoritative: the agent is skipped when HSA_TOOLS_LIB or HSA_ENABLE_DEBUG is already set, and the other two are defaults rather than overrides. Same rule in the case-optimization script. Claude-Session: https://claude.ai/code/session_013573Qr8zEMdYLkP4XyVfiy
1 parent 8ac4682 commit dc73590

3 files changed

Lines changed: 79 additions & 7 deletions

File tree

.github/scripts/run_case_optimization.sh

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,13 @@ for case in "${benchmarks[@]}"; do
107107
# address with nothing to act on. Both variables are inert until a fault;
108108
# the debug agent is what gives CCE a faulting kernel at all, and is set
109109
# only where its library is actually reachable.
110-
export OFFLOAD_TRACK_ALLOCATION_TRACES=true
111-
export OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES=8
112-
if [ -n "${ROCM_PATH:-}" ] && [ -f "$ROCM_PATH/lib/librocm-debug-agent.so.2" ]; then
110+
export OFFLOAD_TRACK_ALLOCATION_TRACES="${OFFLOAD_TRACK_ALLOCATION_TRACES:-true}"
111+
export OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES="${OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES:-8}"
112+
# Skipped when the caller already chose a tool, or is collecting a GPU core
113+
# dump -- the agent is mutually exclusive with one, so loading it anyway
114+
# would leave them with no dump and no reason why.
115+
if [ -z "${HSA_TOOLS_LIB:-}" ] && [ -z "${HSA_ENABLE_DEBUG:-}" ] \
116+
&& [ -n "${ROCM_PATH:-}" ] && [ -f "$ROCM_PATH/lib/librocm-debug-agent.so.2" ]; then
113117
export HSA_TOOLS_LIB=librocm-debug-agent.so.2
114118
fi
115119

toolchain/mfc/gpu_diagnostics.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,21 @@ def fault_diagnostic_env(base: dict) -> dict:
8282
Returns a new dict: these run in worker threads, and mutating a shared
8383
environment would leak settings into every concurrent case.
8484
"""
85-
env = {
86-
**base,
85+
env = dict(base)
86+
87+
# Never clobber a setting the caller made. `mfc.sh test` and `mfc.sh bench`
88+
# are developer commands, not just CI entry points, so anyone debugging by
89+
# hand has to be able to choose their own values and have them survive.
90+
defaults = {
8791
# Says whether the faulting address was ever a real host allocation,
8892
# separating an overrun of a known array from a wild pointer.
8993
"OFFLOAD_TRACK_ALLOCATION_TRACES": "true",
9094
# Host stack traces for the most recent kernel launches. The runtime
9195
# advertises this itself in the fault message ("0 now, up to 8").
9296
"OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES": "8",
9397
}
98+
for name, value in defaults.items():
99+
env.setdefault(name, value)
94100

95101
# The only thing that gives CCE a faulting kernel. Measured on Frontier
96102
# under --gpu acc: it prints "Disassembly for function
@@ -122,8 +128,20 @@ def fault_diagnostic_env(base: dict) -> dict:
122128
# own fault report. Worst realistic case is one working diagnostic replacing
123129
# another strictly more detailed one; if a real AFAR fault shows otherwise,
124130
# gate this on the lane.
125-
agent = rocm_debug_agent_path()
126-
if agent is not None:
131+
# Two ways the caller can say "stay out of my way", both of which mean a
132+
# human is already debugging this run by hand:
133+
#
134+
# HSA_TOOLS_LIB already set -- they chose a tool; do not replace it.
135+
# HSA_ENABLE_DEBUG set -- they are collecting a GPU core dump, and
136+
# the agent is mutually exclusive with one.
137+
# Loading it anyway yields "Failed to enable
138+
# debug interface" and no dump, with the
139+
# cause being something the harness did
140+
# behind them.
141+
#
142+
# The same reasoning covers an attached rocgdb, which trips the same
143+
# already-attached path.
144+
if "HSA_TOOLS_LIB" not in env and not env.get("HSA_ENABLE_DEBUG") and rocm_debug_agent_path() is not None:
127145
env["HSA_TOOLS_LIB"] = ROCM_DEBUG_AGENT
128146

129147
return env

toolchain/mfc/test/test_gpu_fault_diagnostics.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,3 +504,53 @@ def test_a_missing_agent_report_on_a_gpu_fault_is_called_out():
504504

505505
assert "rocm_debug_agent_path() is not None" in src
506506
assert "format has changed" in src
507+
508+
509+
def test_a_core_dump_session_is_not_hijacked(monkeypatch):
510+
"""`mfc.sh test` is a developer command, not only a CI entry point.
511+
512+
The debug agent and ROCr core dumps are mutually exclusive -- measured. So
513+
setting the agent behind someone who has asked for a dump gives them
514+
"Failed to enable debug interface" and no dump, caused by the harness
515+
rather than by anything they did.
516+
"""
517+
from mfc.gpu_diagnostics import fault_diagnostic_env
518+
519+
monkeypatch.setenv("ROCM_PATH", tmp_agent_dir())
520+
521+
assert "HSA_TOOLS_LIB" in fault_diagnostic_env({})
522+
assert "HSA_TOOLS_LIB" not in fault_diagnostic_env({"HSA_ENABLE_DEBUG": "1"})
523+
524+
525+
def test_an_explicit_tool_choice_is_not_replaced(monkeypatch):
526+
from mfc.gpu_diagnostics import fault_diagnostic_env
527+
528+
monkeypatch.setenv("ROCM_PATH", tmp_agent_dir())
529+
530+
env = fault_diagnostic_env({"HSA_TOOLS_LIB": "libmy-own-tool.so"})
531+
532+
assert env["HSA_TOOLS_LIB"] == "libmy-own-tool.so"
533+
534+
535+
def test_explicit_offload_settings_survive():
536+
"""A developer tuning these by hand must not have them silently reset."""
537+
from mfc.gpu_diagnostics import fault_diagnostic_env
538+
539+
env = fault_diagnostic_env(
540+
{
541+
"OFFLOAD_TRACK_ALLOCATION_TRACES": "false",
542+
"OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES": "2",
543+
}
544+
)
545+
546+
assert env["OFFLOAD_TRACK_ALLOCATION_TRACES"] == "false"
547+
assert env["OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES"] == "2"
548+
549+
550+
def test_the_defaults_still_apply_when_nothing_was_chosen():
551+
from mfc.gpu_diagnostics import fault_diagnostic_env
552+
553+
env = fault_diagnostic_env({})
554+
555+
assert env["OFFLOAD_TRACK_ALLOCATION_TRACES"] == "true"
556+
assert env["OFFLOAD_TRACK_NUM_KERNEL_LAUNCH_TRACES"] == "8"

0 commit comments

Comments
 (0)