[https://nvbugs/6683840][fix] Join the encoder launch before the decoder forward - #18613
Conversation
…der forward torch.fx's tracing flag and its patch of nn.Module.__call__ are process-global, so a dynamo compile on the encoder-launch thread captures the decoder thread's concurrent module calls and dynamo refuses to re-enter. At tp_size 1 the encoder future is now joined before the decoder forward runs, while ready_event stays unsynchronized so encoder kernels still overlap decoder work on their own stream. Signed-off-by: Pranav Shrestha <254760092+pranav-nvidia@users.noreply.github.com>
a4e5c28 to
7f870dd
Compare
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review. WalkthroughThe non-TP encoder submission path now resolves the launch future before decoder execution continues. It stores the completed encoder result for later polling while deferring CUDA readiness synchronization. Tests now verify this lifecycle. ChangesEncoder lifecycle
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: ⚪ Minimal · up to The encoder launch now completes before decoder execution to prevent concurrent tracing failures while preserving asynchronous device work. This localized change has targeted lifecycle coverage, and no actionable merge-blocking risk remains. Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Description checkExplanation The description clearly explains the failure mode, solution, preserved GPU overlap, affected paths, test coverage, and contract change. The required sections are present and the checklist is completed.
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
/bot run --disable-fail-fast |
|
PR_Github #71102 [ run ] triggered by Bot. Commit: |
cascade812
left a comment
There was a problem hiding this comment.
LGTM, thanks for the fix!
|
PR_Github #71102 [ run ] completed with state
|
|
/bot run |
|
PR_Github #71288 [ run ] triggered by Bot. Commit: |
|
PR_Github #71288 [ run ] completed with state
|
|
/bot run |
|
PR_Github #71319 [ run ] triggered by Bot. Commit: |
|
PR_Github #71319 [ run ] completed with state
|
|
/bot run |
|
PR_Github #71442 [ run ] triggered by Bot. Commit: |
|
PR_Github #71442 [ run ] completed with state
|
|
/bot run |
|
PR_Github #71560 [ run ] triggered by Bot. Commit: |
|
PR_Github #71560 [ run ] completed with state |
Dev Engineer Review
_submit_encoder_stepnow joins the encoder launch future fortp_size == 1.PendingEncoderStep._poll_encoder_steps.tp_size > 1path remains unchanged.torch.fxtracing andtorch.compileactivity across threads.QA Engineer Review
tests/unittest/_torch/executor/test_py_executor.py._submit_encoder_stepand readiness remains deferred to_poll_encoder_steps.tests/integration/test_lists/.Description
At
tp_size == 1,_submit_encoder_stepreturned as soon as the encoder step was submitted, so the encoder forward ran on theencoder-launchworker while the executor thread ran the decoder forward. Both callLayerNorm.forward, which carries@maybe_compile(dynamic=True).torch.fx's tracing state is process-global, not thread-local:Tracer.tracesets_is_fx_tracing_flagand patchestorch.nn.Module.__call__for the whole process, and an ordinarytorch.compilereaches it through AOTAutograd'smake_fx. A fresh compile on either thread therefore captured the other thread's module calls, and dynamo raisedDetected that you are using FX to symbolically trace a dynamo-optimized function, surfaced asRequestError. When the executor thread was the victim the exception ended the event loop and failed every in-flight request.This joins the encoder future before the decoder forward runs, so the two Python launches no longer overlap.
ready_eventis deliberately left unsynchronized and publication stays in_poll_encoder_steps, so encoder GPU work still overlaps decoder work. Thetp_size > 1path is unchanged.Throughput is unchanged within noise on whisper-large-v3 and whisper-tiny (fp16, SM120, batch 1/8/32, encoder CUDA graphs on and off), except large-v3 / no encoder graphs / batch 1 at about 3%. The GIL already interleaved the two threads' Python, so only the GPU-stream overlap was load-bearing and that is preserved.
modeling_bart.pyandmodeling_parakeet.pyshare the exposure: the worker is created fromis_encoder_decoderalone and both use the compiledLayerNorm.modeling_t5.pyusesRMSNorm, which is not compiled.For review: this changes the fire-and-forget contract added in #16706, which that PR pinned in
test_async_encoder_step_lifecycle.Test Coverage
tests/unittest/_torch/executor/test_py_executor.py::test_async_encoder_step_lifecycle— updated to the new contract: the launch is joined inline, while publication still waits onready_eventrather than on the future.tests/unittest/_torch/executor/— 1769 passed, 1 skipped, 3 xfailed, with the same 10 pre-existingtest_overlap_scheduler.pyerrors as an unpatched control run on the same tree.PR Checklist
GitHub Bot Help
To see a list of available CI bot commands, please comment
/bot help.