Repository navigation
fix(compile): format Inductor's implicit-fallback log text only when emitted - #3073
Merged
Merged
Conversation
…emitted Before torch 2.13, GraphLowering.call_function builds OperatorIssue.operator_str(target, args, kwargs) eagerly as the argument of a log.info call that is normally filtered out. The text is the full str() of every argument's Inductor IR, and ExternKernel.__str__ prints its inputs recursively, so for an op that falls back late in a long chain of custom ops building it can keep a cold compile busy for a long time with no log output and an idle GPU, which looks like a startup hang. torch 2.13 defers this with LazyString (pytorch/pytorch#185951). Do the same on older torch: operator_str returns an object that formats the original text in __str__. All pre-2.13 callers only stringify the result (the log call's %s and the OperatorIssue subclasses' f-strings), so emitted logs and exception messages are unchanged. No-op from torch 2.13 on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
valarLip
approved these changes
Nov 10, 2026
rdoshi-amd
added a commit
to rdoshi-amd/ATOM
that referenced
this pull request
Nov 10, 2026
Brings in main through 03b584b (ROCm#3109 V4.1 gfx1250 single-launch decode step, ROCm#3169, ROCm#3167, ROCm#3052, ROCm#3073, ROCm#3153, README news). One conflict, in model_runner.py: ROCm#3109's step override (`_step_override` / `_served`) and this branch's model head output (`compute_head`) sit side by side, in __init__ and as two branches of postprocess's verdict (a tuple head output; an overridden step's `verify_outputs`). The two are exclusive: an overridden step returns no head output. The hi runner test's stand-in runner gains ROCm#3109's `_served` and the stream argument of `forward_done_event.record`.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Motivation
On torch < 2.13 a cold
--level 3compile can sit for a long time with no log output and an idle GPU, which looks like a hung startup. A Python stack dump of every rank shows the same frames:with dozens of nested
ExternKernel.__str__frames aboveoperator_str.We hit it with DeepSeek-V4.1-Flash + DSpark whenever the first graph (
backbone) is served from the Inductor FX graph cache and the second one (backbone_late) is not, for example after changing--max-num-batched-tokens(which changes only the late graph's key) while keeping/tmp/torchinductor_<user>. The custom ops are then lowered for the first time inside the late graph, deep in a chain of extern kernels.Technical Details
Root cause (PyTorch). When an op has no Inductor lowering,
GraphLowering.call_functionregisters an implicit fallback and logs it. Before torch 2.13 the log call isso
operator_strruns even though INFO is filtered out. It builds the fullstr()of every argument's IR, andExternKernel.__str__prints its inputs recursively, so for an op whose inputs come from a long chain of custom ops the text is very large and building it dominates the compile. torch 2.13 defers it withLazyString(error.operator_str, ...)(pytorch/pytorch#185951); 2.10, 2.11 and 2.12 all format eagerly. ROCm images that ATOM ships today are on torch 2.10.Fix.
atom/utils/compiler_inferface.py(already the place ATOM adapts Inductor/Triton at import, next to_patch_triton_cluster_dims_for_rocm) replacesOperatorIssue.operator_stron torch < 2.13 with a function that returns a small object whose__str__calls the original. This is the 2.13 behaviour applied to older torch:log.infonever stringifies its argument, so nothing is built.OperatorIssueis raised (its subclasses embed the text through f-strings),str()produces exactly the original text. On 2.10-2.12 these are the only callers.LazyString.__str__must receive a realstrfromoperator_str.Test Plan
Unit (CPU):
tests/test_compiler_interface.pylog.infoin the pre-2.13 call shape does not print the IR arguments;LoweringExceptionmessage still contains the operator text.(Skipped on torch >= 2.13.)
E2E: DeepSeek-V4.1-Flash, TP4 with DP attention + EP, DSpark,
--level 3, stock torch 2.10exc.py. The Inductor cache dir is a copy of one populated by earlier runs at other--max-num-batched-tokensvalues, and the ATOM compile cache is empty, so the backbone graph hits the Inductor cache and the late graph is lowered cold.Test Result
OperatorIssue.operator_strunderGraphLowering.call_function; still there when stopped by the watchdogWithout this change, a run with a cold Inductor cache for both graphs did not hit the slow path (the custom ops get their fallbacks registered early in the backbone graph, where their inputs are shallow), which is why the problem only shows up after a partial Inductor cache hit.
Unit: the new tests and the existing ones in
tests/test_compiler_interface.pypass on torch 2.10. Black is clean; Ruff reports no new diagnostics on the changed files.Submission Checklist
🤖 Generated with Claude Code