[Intel GPU] Enable pipeline parallelism on XPU (#23645)
This commit is contained in:
@@ -31,6 +31,7 @@ from sglang.srt.managers.utils import (
|
|||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, PPProxyTensors
|
||||||
from sglang.srt.sampling.sampling_params import SamplingParams
|
from sglang.srt.sampling.sampling_params import SamplingParams
|
||||||
from sglang.srt.utils import DynamicGradMode, broadcast_pyobj, point_to_point_pyobj
|
from sglang.srt.utils import DynamicGradMode, broadcast_pyobj, point_to_point_pyobj
|
||||||
|
from sglang.srt.utils.common import get_device_module, is_xpu
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -129,7 +130,9 @@ class SchedulerPPMixin:
|
|||||||
self.last_mbs[next_mb_id] = self.mbs[next_mb_id]
|
self.last_mbs[next_mb_id] = self.mbs[next_mb_id]
|
||||||
if not self.pp_group.is_last_rank:
|
if not self.pp_group.is_last_rank:
|
||||||
if self.cur_batch:
|
if self.cur_batch:
|
||||||
torch.cuda.current_stream().wait_event(self.launch_event)
|
self.device_module.current_stream().wait_event(
|
||||||
|
self.launch_event
|
||||||
|
)
|
||||||
with torch.profiler.record_function(
|
with torch.profiler.record_function(
|
||||||
"send_proxy_dict_to_next_stage"
|
"send_proxy_dict_to_next_stage"
|
||||||
):
|
):
|
||||||
@@ -304,7 +307,9 @@ class SchedulerPPMixin:
|
|||||||
transferred_rids, async_send=True
|
transferred_rids, async_send=True
|
||||||
)
|
)
|
||||||
if self.cur_batch:
|
if self.cur_batch:
|
||||||
torch.cuda.current_stream().wait_event(self.launch_event)
|
self.device_module.current_stream().wait_event(
|
||||||
|
self.launch_event
|
||||||
|
)
|
||||||
self.send_proxy_work = self._pp_send_dict_to_next_stage(
|
self.send_proxy_work = self._pp_send_dict_to_next_stage(
|
||||||
result.pp_hidden_states_proxy_tensors.tensors,
|
result.pp_hidden_states_proxy_tensors.tensors,
|
||||||
async_send=True,
|
async_send=True,
|
||||||
@@ -485,7 +490,9 @@ class SchedulerPPMixin:
|
|||||||
transferred_rids, async_send=True
|
transferred_rids, async_send=True
|
||||||
)
|
)
|
||||||
if self.cur_batch and not self.cur_batch.forward_mode.is_prebuilt():
|
if self.cur_batch and not self.cur_batch.forward_mode.is_prebuilt():
|
||||||
torch.cuda.current_stream().wait_event(self.launch_event)
|
self.device_module.current_stream().wait_event(
|
||||||
|
self.launch_event
|
||||||
|
)
|
||||||
self.send_proxy_work = self._pp_send_dict_to_next_stage(
|
self.send_proxy_work = self._pp_send_dict_to_next_stage(
|
||||||
result.pp_hidden_states_proxy_tensors.tensors,
|
result.pp_hidden_states_proxy_tensors.tensors,
|
||||||
async_send=True,
|
async_send=True,
|
||||||
@@ -525,9 +532,7 @@ class SchedulerPPMixin:
|
|||||||
]
|
]
|
||||||
self.mb_metadata: List[Optional[PPBatchMetadata]] = [None] * self.pp_loop_size
|
self.mb_metadata: List[Optional[PPBatchMetadata]] = [None] * self.pp_loop_size
|
||||||
self.pp_outputs: Optional[PPProxyTensors] = None
|
self.pp_outputs: Optional[PPProxyTensors] = None
|
||||||
self.last_rank_comm_queue: deque[Tuple[torch.cuda.Event, PPProxyTensors]] = (
|
self.last_rank_comm_queue: deque[Tuple[torch.Event, PPProxyTensors]] = deque()
|
||||||
deque()
|
|
||||||
)
|
|
||||||
|
|
||||||
self.send_req_work = []
|
self.send_req_work = []
|
||||||
self.send_proxy_work = []
|
self.send_proxy_work = []
|
||||||
@@ -611,21 +616,21 @@ class SchedulerPPMixin:
|
|||||||
"hidden_states": torch.zeros(
|
"hidden_states": torch.zeros(
|
||||||
(current_seq_len, model_config.hidden_size),
|
(current_seq_len, model_config.hidden_size),
|
||||||
dtype=model_config.dtype,
|
dtype=model_config.dtype,
|
||||||
device="cuda",
|
device=self.device,
|
||||||
),
|
),
|
||||||
"residual": torch.zeros(
|
"residual": torch.zeros(
|
||||||
(current_seq_len, model_config.hidden_size),
|
(current_seq_len, model_config.hidden_size),
|
||||||
dtype=model_config.dtype,
|
dtype=model_config.dtype,
|
||||||
device="cuda",
|
device=self.device,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
pp_proxy = PPProxyTensors(proxy_tensors)
|
pp_proxy = PPProxyTensors(proxy_tensors)
|
||||||
|
|
||||||
# Measure latency with CUDA synchronization for accurate timing
|
# Measure latency with device synchronization for accurate timing
|
||||||
|
device_module = get_device_module()
|
||||||
# Synchronize before starting timing to ensure clean measurement
|
# Synchronize before starting timing to ensure clean measurement
|
||||||
if torch.cuda.is_available():
|
device_module.synchronize()
|
||||||
torch.cuda.synchronize()
|
|
||||||
|
|
||||||
start = time.perf_counter()
|
start = time.perf_counter()
|
||||||
batch.prepare_for_extend()
|
batch.prepare_for_extend()
|
||||||
@@ -639,8 +644,7 @@ class SchedulerPPMixin:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Synchronize after forward to ensure GPU operations complete
|
# Synchronize after forward to ensure GPU operations complete
|
||||||
if torch.cuda.is_available():
|
device_module.synchronize()
|
||||||
torch.cuda.synchronize()
|
|
||||||
|
|
||||||
latency_seconds = time.perf_counter() - start
|
latency_seconds = time.perf_counter() - start
|
||||||
latency_ms = latency_seconds * 1e3 # Convert to milliseconds
|
latency_ms = latency_seconds * 1e3 # Convert to milliseconds
|
||||||
@@ -858,7 +862,11 @@ class SchedulerPPMixin:
|
|||||||
self: Scheduler,
|
self: Scheduler,
|
||||||
next_first_rank_mb_id: int,
|
next_first_rank_mb_id: int,
|
||||||
next_mb_id: int,
|
next_mb_id: int,
|
||||||
) -> Tuple[PPProxyTensors, GenerationBatchResult, torch.cuda.Event]:
|
) -> Tuple[
|
||||||
|
Optional[PPProxyTensors],
|
||||||
|
Optional[GenerationBatchResult],
|
||||||
|
Optional[torch.Event],
|
||||||
|
]:
|
||||||
self._pp_commit_comm_work(work=self.send_output_work)
|
self._pp_commit_comm_work(work=self.send_output_work)
|
||||||
(
|
(
|
||||||
next_pp_outputs,
|
next_pp_outputs,
|
||||||
@@ -1054,7 +1062,7 @@ class SchedulerPPMixin:
|
|||||||
self: Scheduler,
|
self: Scheduler,
|
||||||
next_first_rank_mb_id: int,
|
next_first_rank_mb_id: int,
|
||||||
mbs: List[ScheduleBatch],
|
mbs: List[ScheduleBatch],
|
||||||
last_rank_comm_queue: deque[Tuple[torch.cuda.Event, PPProxyTensors]],
|
last_rank_comm_queue: deque,
|
||||||
pp_outputs: PPProxyTensors | None,
|
pp_outputs: PPProxyTensors | None,
|
||||||
) -> List[P2PWork]:
|
) -> List[P2PWork]:
|
||||||
send_output_work = []
|
send_output_work = []
|
||||||
@@ -1063,7 +1071,7 @@ class SchedulerPPMixin:
|
|||||||
if mbs[next_first_rank_mb_id] is not None:
|
if mbs[next_first_rank_mb_id] is not None:
|
||||||
q_event, pp_outputs_to_send = last_rank_comm_queue.popleft()
|
q_event, pp_outputs_to_send = last_rank_comm_queue.popleft()
|
||||||
if not mbs[next_first_rank_mb_id].forward_mode.is_prebuilt():
|
if not mbs[next_first_rank_mb_id].forward_mode.is_prebuilt():
|
||||||
torch.cuda.current_stream().wait_event(q_event)
|
self.device_module.current_stream().wait_event(q_event)
|
||||||
with torch.profiler.record_function("send_res_dict_to_next_stage"):
|
with torch.profiler.record_function("send_res_dict_to_next_stage"):
|
||||||
send_output_work = self._pp_send_dict_to_next_stage(
|
send_output_work = self._pp_send_dict_to_next_stage(
|
||||||
pp_outputs_to_send.tensors,
|
pp_outputs_to_send.tensors,
|
||||||
@@ -1087,34 +1095,60 @@ class SchedulerPPMixin:
|
|||||||
next_mb_id: int,
|
next_mb_id: int,
|
||||||
mbs: List[ScheduleBatch],
|
mbs: List[ScheduleBatch],
|
||||||
mb_metadata: List[PPBatchMetadata],
|
mb_metadata: List[PPBatchMetadata],
|
||||||
last_rank_comm_queue: deque[Tuple[torch.cuda.Event, PPProxyTensors]],
|
last_rank_comm_queue: deque[Tuple[torch.Event, PPProxyTensors]],
|
||||||
pp_outputs: PPProxyTensors | None,
|
pp_outputs: PPProxyTensors | None,
|
||||||
) -> Tuple[PPProxyTensors, List[P2PWork], torch.cuda.Event]:
|
) -> Tuple[
|
||||||
|
Optional[PPProxyTensors],
|
||||||
|
Optional[GenerationBatchResult],
|
||||||
|
Optional[torch.Event],
|
||||||
|
List[P2PWork],
|
||||||
|
]:
|
||||||
next_pp_outputs = None
|
next_pp_outputs = None
|
||||||
d2h_event = None
|
d2h_event = None
|
||||||
batch_result = None
|
batch_result = None
|
||||||
send_output_work = self._pp_send_output_to_next_stage(
|
send_output_work = []
|
||||||
next_first_rank_mb_id,
|
|
||||||
mbs,
|
|
||||||
last_rank_comm_queue,
|
|
||||||
pp_outputs,
|
|
||||||
)
|
|
||||||
|
|
||||||
if mbs[next_mb_id] is not None:
|
# On CUDA, isend is async: it enqueues to the stream and returns,
|
||||||
|
# so every rank can send first safely. On some backends isend is
|
||||||
|
# effectively blocking and does not return until the peer posts a
|
||||||
|
# matching recv; if every PP rank sends first, all ranks block
|
||||||
|
# waiting for a receiver and the ring deadlocks. Order send/recv
|
||||||
|
# by pp_rank parity (even: send->recv, odd: recv->send) so each
|
||||||
|
# adjacent pair has one sender and one receiver posted at the
|
||||||
|
# same time.
|
||||||
|
|
||||||
|
# CUDA: send first
|
||||||
|
# XPU: even ranks send first, odd ranks recv first.
|
||||||
|
send_first = (not is_xpu()) or ((self.pp_rank % 2) == 0)
|
||||||
|
|
||||||
|
def _do_send():
|
||||||
|
return self._pp_send_output_to_next_stage(
|
||||||
|
next_first_rank_mb_id,
|
||||||
|
mbs,
|
||||||
|
last_rank_comm_queue,
|
||||||
|
pp_outputs,
|
||||||
|
)
|
||||||
|
|
||||||
|
def _do_recv():
|
||||||
|
nonlocal next_pp_outputs, batch_result, d2h_event
|
||||||
|
if mbs[next_mb_id] is None or mbs[next_mb_id].forward_mode.is_prebuilt():
|
||||||
|
return
|
||||||
with torch.profiler.record_function("recv_res_dict_from_prev_stage"):
|
with torch.profiler.record_function("recv_res_dict_from_prev_stage"):
|
||||||
next_pp_outputs = None
|
next_pp_outputs = PPProxyTensors(self._pp_recv_dict_from_prev_stage())
|
||||||
if not mbs[next_mb_id].forward_mode.is_prebuilt():
|
with self.copy_stream_ctx:
|
||||||
next_pp_outputs = PPProxyTensors(
|
self.copy_stream.wait_stream(self.schedule_stream)
|
||||||
self._pp_recv_dict_from_prev_stage()
|
batch_result = self._pp_prep_batch_result(
|
||||||
)
|
mbs[next_mb_id], mb_metadata[next_mb_id], next_pp_outputs
|
||||||
if not mbs[next_mb_id].forward_mode.is_prebuilt():
|
)
|
||||||
with self.copy_stream_ctx:
|
d2h_event = self.device_module.Event()
|
||||||
self.copy_stream.wait_stream(self.schedule_stream)
|
d2h_event.record(self.device_module.current_stream())
|
||||||
batch_result = self._pp_prep_batch_result(
|
|
||||||
mbs[next_mb_id], mb_metadata[next_mb_id], next_pp_outputs
|
if send_first:
|
||||||
)
|
send_output_work = _do_send()
|
||||||
d2h_event = torch.cuda.Event()
|
_do_recv()
|
||||||
d2h_event.record(torch.cuda.current_stream())
|
else:
|
||||||
|
_do_recv()
|
||||||
|
send_output_work = _do_send()
|
||||||
|
|
||||||
return next_pp_outputs, batch_result, d2h_event, send_output_work
|
return next_pp_outputs, batch_result, d2h_event, send_output_work
|
||||||
|
|
||||||
@@ -1123,7 +1157,7 @@ class SchedulerPPMixin:
|
|||||||
mb_id: int,
|
mb_id: int,
|
||||||
pp_proxy_tensors: PPProxyTensors,
|
pp_proxy_tensors: PPProxyTensors,
|
||||||
mb_metadata: List[Optional[PPBatchMetadata]],
|
mb_metadata: List[Optional[PPBatchMetadata]],
|
||||||
last_rank_comm_queue: deque[Tuple[torch.cuda.Event, PPProxyTensors]],
|
last_rank_comm_queue: deque,
|
||||||
):
|
):
|
||||||
with torch.profiler.record_function("run_batch"):
|
with torch.profiler.record_function("run_batch"):
|
||||||
with self.forward_stream_ctx:
|
with self.forward_stream_ctx:
|
||||||
@@ -1132,8 +1166,8 @@ class SchedulerPPMixin:
|
|||||||
mb_metadata[mb_id] = PPBatchMetadata(
|
mb_metadata[mb_id] = PPBatchMetadata(
|
||||||
can_run_cuda_graph=result.can_run_cuda_graph,
|
can_run_cuda_graph=result.can_run_cuda_graph,
|
||||||
)
|
)
|
||||||
event = torch.cuda.Event()
|
event = self.device_module.Event()
|
||||||
event.record(torch.cuda.current_stream())
|
event.record(self.device_module.current_stream())
|
||||||
if self.pp_group.is_last_rank:
|
if self.pp_group.is_last_rank:
|
||||||
# (last rank) buffer the outputs for async batch depth
|
# (last rank) buffer the outputs for async batch depth
|
||||||
last_rank_comm_queue.append(
|
last_rank_comm_queue.append(
|
||||||
|
|||||||
Reference in New Issue
Block a user