Skip to content

Commit 3d204df

Browse files
Revert "[Perf][ROCm] Dual-stream decode with hipgraphs" (#52024)
Signed-off-by: simondanielsson <simon.danielsson99@hotmail.com> Co-authored-by: Andreas Karatzas <akaratza@amd.com>
1 parent 2ac1f68 commit 3d204df

2 files changed

Lines changed: 55 additions & 55 deletions

File tree

vllm/model_executor/layers/fused_moe/runner/moe_runner.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -573,17 +573,12 @@ def _apply_quant_method(
573573
router_logits: torch.Tensor,
574574
shared_experts_input: torch.Tensor | None,
575575
input_ids: torch.Tensor | None = None,
576-
shared_experts_overlapping: bool = False,
577576
) -> tuple[torch.Tensor | None, torch.Tensor]:
578577
"""Run expert routing and the fused MoE kernel via the quant method.
579578
580579
Orchestrates shared expert execution (before/after), expert selection
581580
via the router, and the actual fused MoE computation. Returns
582581
(shared_expert_output, fused_expert_output).
583-
584-
`shared_experts_overlapping` should be True only if using multi-stream
585-
overlap. Then the shared expert was already launched in a separate
586-
stream, so the results only have to be awaited here.
587582
"""
588583
self._maybe_apply_shared_experts(
589584
shared_experts_input, SharedExpertsOrder.NO_OVERLAP
@@ -613,9 +608,10 @@ def _apply_quant_method(
613608
shared_experts_input=shared_experts_input,
614609
)
615610

616-
if shared_experts_overlapping:
617-
assert self._shared_experts is not None
618-
self._shared_experts.wait()
611+
self._maybe_apply_shared_experts(
612+
shared_experts_input,
613+
SharedExpertsOrder.MULTI_STREAM_OVERLAPPED,
614+
)
619615

620616
return (
621617
self._shared_experts.output if self._shared_experts is not None else None,
@@ -637,6 +633,18 @@ def _sequence_parallel_context(self):
637633
else nullcontext()
638634
)
639635

636+
def _maybe_sync_shared_experts_stream(
637+
self,
638+
shared_experts_input: torch.Tensor | None,
639+
):
640+
# If router/gate provided, then apply it here.
641+
# (Note: This code runs only when "overlapped mode" is on to allow
642+
# parallel execution of shared experts with the RoutedExperts via
643+
# separate cuda stream)
644+
if self._shared_experts is not None:
645+
assert shared_experts_input is not None
646+
self._shared_experts.maybe_sync_shared_experts_stream(shared_experts_input)
647+
640648
def _maybe_add_zero_expert_output(
641649
self,
642650
result: torch.Tensor,
@@ -841,13 +849,8 @@ def _forward_impl(
841849
# TODO(bnell): this can be removed after MK migration is complete.
842850
self.routed_experts._ensure_moe_quant_config_init()
843851

844-
# If using multi-stream overlap for shared experts, we must launch it
845-
# before routed expert dispatch.
846-
shared_experts_overlapping = False
847-
if self._shared_experts is not None:
848-
shared_experts_overlapping = self._shared_experts.maybe_forward_async(
849-
shared_experts_input
850-
)
852+
# Sync aux and main stream for shared expert multi-stream overlap.
853+
self._maybe_sync_shared_experts_stream(shared_experts_input)
851854

852855
# If the Runner holds the gate, apply it after the stream sync,
853856
# so it can run overlapped with the
@@ -873,7 +876,6 @@ def _forward_impl(
873876
router_logits=router_logits,
874877
shared_experts_input=shared_experts_input,
875878
input_ids=input_ids,
876-
shared_experts_overlapping=shared_experts_overlapping,
877879
)
878880

879881
return self._maybe_combine(

vllm/model_executor/layers/fused_moe/runner/shared_experts.py

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,6 @@ def __init__(
7171
if self._stream is not None:
7272
logger.debug_once("Enabled separate cuda stream for MoE shared_experts")
7373

74-
if self._stream is not None:
75-
# One pair per DBO ubatch id.
76-
self._input_ready_event = [torch.cuda.Event(), torch.cuda.Event()]
77-
self._output_ready_event = [torch.cuda.Event(), torch.cuda.Event()]
78-
7974
# TODO(bnell): Hack for elastic_ep. Get rid of this
8075
def _set_moe_config(self, new_moe_config: FusedMoEConfig):
8176
self.moe_config = new_moe_config
@@ -101,14 +96,6 @@ def _disable_shared_experts_overlap(self) -> bool:
10196
and parallel_config.all2all_backend not in _EPLB_OVERLAP_SAFE_BACKENDS
10297
) or parallel_config.use_fi_nvl_two_sided_kernels
10398

104-
@property
105-
def _should_enable_stream_overlap_heuristic(self) -> bool:
106-
# On ROCm, empirically it's shown that only DPA deployments benefit from
107-
# multi-stream shared experts
108-
if not current_platform.is_rocm():
109-
return True
110-
return self._moe_config.moe_parallel_config.dp_size > 1
111-
11299
def _determine_shared_experts_order(
113100
self,
114101
hidden_states: torch.Tensor,
@@ -120,43 +107,49 @@ def _determine_shared_experts_order(
120107
return SharedExpertsOrder.MK_INTERNAL_OVERLAPPED
121108

122109
should_run_shared_in_aux_stream = (
123-
current_platform.is_cuda_alike()
110+
current_platform.is_cuda()
124111
and self._stream is not None
125112
and hidden_states.shape[0]
126113
<= envs.VLLM_SHARED_EXPERTS_STREAM_TOKEN_THRESHOLD
127-
and self._should_enable_stream_overlap_heuristic
128114
)
129115

130116
if should_run_shared_in_aux_stream:
131117
return SharedExpertsOrder.MULTI_STREAM_OVERLAPPED
132118
else:
133119
return SharedExpertsOrder.NO_OVERLAP
134120

135-
def maybe_forward_async(self, shared_experts_input: torch.Tensor) -> bool:
136-
"""Enqueue shared experts on the aux stream without waiting for them.
137-
138-
Returns true if the shared experts were enqueued, false otherwise. Call
139-
`wait` to wait for the shared experts to finish if this returns true.
140-
"""
141-
if (
142-
self._determine_shared_experts_order(shared_experts_input)
143-
!= SharedExpertsOrder.MULTI_STREAM_OVERLAPPED
144-
):
145-
return False
146-
assert self._stream is not None
147-
idx = self._output_idx
148-
assert self._output[idx] is None
149-
self._input_ready_event[idx].record(current_stream())
121+
def maybe_sync_shared_experts_stream(
122+
self,
123+
shared_experts_input: torch.Tensor,
124+
):
125+
experts_order = self._determine_shared_experts_order(shared_experts_input)
126+
127+
if experts_order == SharedExpertsOrder.MULTI_STREAM_OVERLAPPED:
128+
assert self._stream is not None
129+
130+
# Record that the clone will be used by shared_experts_stream
131+
# to avoid gc issue from deallocation of hidden_states_clone
132+
# For more details: https://docs.pytorch.org/docs/stable/generated/torch.Tensor.record_stream.html # noqa: E501
133+
# NOTE: We don't need shared_output.record_stream(current_stream())
134+
# because we synch the streams before using shared_output.
135+
shared_experts_input.record_stream(self._stream)
136+
137+
# Mark sync start point for the aux stream since we will
138+
# run in parallel with router/gate.
139+
self._stream.wait_stream(current_stream())
140+
141+
def _run_in_aux_stream(
142+
self,
143+
shared_experts_input: torch.Tensor,
144+
) -> torch.Tensor:
145+
# TODO: assert that maybe_sync_shared_experts_stream has been called.
146+
147+
# Run shared experts in parallel on a separate stream.
150148
with torch.cuda.stream(self._stream):
151-
self._input_ready_event[idx].wait(self._stream)
152-
self._output[idx] = self._layer(shared_experts_input)
153-
self._output_ready_event[idx].record(self._stream)
154-
return True
149+
output = self._layer(shared_experts_input)
150+
current_stream().wait_stream(self._stream)
155151

156-
def wait(self) -> None:
157-
"""Block the main stream until `maybe_forward_async` output is ready."""
158-
assert self._stream is not None
159-
self._output_ready_event[self._output_idx].wait(current_stream())
152+
return output
160153

161154
@property
162155
def _output_idx(self) -> int:
@@ -181,6 +174,11 @@ def forward(
181174

182175
assert self._output[self._output_idx] is None
183176

184-
self._output[self._output_idx] = self._layer(shared_experts_input)
177+
if order == SharedExpertsOrder.MULTI_STREAM_OVERLAPPED:
178+
self._output[self._output_idx] = self._run_in_aux_stream(
179+
shared_experts_input
180+
)
181+
else:
182+
self._output[self._output_idx] = self._layer(shared_experts_input)
185183

186184
assert self._output[self._output_idx] is not None

0 commit comments

Comments
 (0)