class BeamAllReduceWorkspace:
"""Reuse FlashInfer's multicast allocation and Lamport generation protocol."""
@classmethod
def create(
cls,
group: torch.distributed.ProcessGroup,
hidden_size: int,
max_tokens: int,
dtype: torch.dtype,
*,
device_group: torch.distributed.ProcessGroup | None = None,
) -> "BeamAllReduceWorkspace | None":
# The CUDA epilogue handles one packed load per thread.
if (
group.size() not in (2, 4, 8)
or dtype != torch.bfloat16
or hidden_size % 1024
or not 1024 <= hidden_size <= 8192
or not has_flashinfer()
):
return None
from flashinfer.comm.mnnvl import (
TorchDistBackend,
all_ranks_agree,
is_multicast_supported,
)
device = torch.accelerator.current_device_index()
supported = torch.cuda.get_device_capability(device)[0] in (9, 10)
supported = supported and is_multicast_supported(device)
if not all_ranks_agree(TorchDistBackend(group=group), supported):
return None
return cls(group, hidden_size, max_tokens, device_group=device_group)
def __init__(
self,
group: torch.distributed.ProcessGroup,
hidden_size: int,
max_tokens: int,
*,
device_group: torch.distributed.ProcessGroup | None = None,
) -> None:
from flashinfer.comm import create_allreduce_fusion_workspace
from flashinfer.comm.mnnvl import TorchDistBackend
self.world_size = group.size()
self.rank = torch.distributed.get_rank(group)
self.hidden_size = hidden_size
self.max_tokens = max_tokens
self.device_group = device_group
self.all_gather: Callable[[torch.Tensor], torch.Tensor] | None = None
# Scale one-shot cutoffs by the BF16 payload staged across all ranks.
token_bytes = hidden_size * 2
rank_token_bytes = self.world_size * token_bytes
self.small_batch_max_tokens = 3200 * 1024 // rank_token_bytes
self.ep_finalize_oneshot_max_tokens = 2560 * 1024 // rank_token_bytes
# GB300 TP2/4, H=5120, top-k=8: one-shot helps at one token;
# two-shot wins through 131072 tokens. Keep the unfused cutoff tunable
# for other geometries instead of imposing an unmeasured crossover.
self.moe_gather_oneshot_max_tokens = 1
self.moe_gather_separate_norm_min_tokens: int | None = None
# Two-shot reserves two rows per token; one-shot needs one per rank.
workspace_tokens = max(
max_tokens,
min(max_tokens, self.small_batch_max_tokens) * self.world_size // 2,
)
self.workspace = create_allreduce_fusion_workspace(
backend="mnnvl",
world_size=self.world_size,
rank=self.rank,
max_token_num=workspace_tokens,
hidden_dim=hidden_size,
dtype=torch.bfloat16,
comm_backend=TorchDistBackend(group=group),
group=group,
)
self.module = _module()
self.allocation_bytes = (
self.workspace.handle.mcast_device_memory.get_allocation_size()
)
self.separate_norm_min_tokens = cdiv(
10 * 1024**2 * self.world_size, token_bytes
)
self.ep_finalize_max_tokens = 640 * 1024**2 // token_bytes