Files
wehub-resource-sync 59a0a3844c
PR Test AMD / cancel-on-close (push) Has been skipped
PR Test NVIDIA ARM / scan (push) Has been skipped
PR Test NVIDIA / cancel-on-close (push) Has been skipped
PR Test AMD / scan (push) Has been skipped
PR Test NVIDIA ARM / cancel-on-close (push) Has been skipped
PR Test NVIDIA / scan (push) Has been skipped
Release Docker Images / build (cu129-torch-2.11.0) (push) Has been skipped
Release Docker Images / build (cu130-torch-2.11.0) (push) Has been skipped
Release PyPI / publish (push) Has been skipped
Scheduler Python Test / test (push) Successful in 27m19s
Docs / build (push) Successful in 28m8s
Scheduler C++ Test / test (push) Successful in 28m19s
Scheduler C++ Test / test-flat (push) Successful in 28m18s
Docs / deploy (push) Has been cancelled
PR Test AMD / finish (push) Has been cancelled
PR Test NVIDIA / finish (push) Has been cancelled
PR Test NVIDIA ARM / finish (push) Has been cancelled
PR Test NVIDIA ARM / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test AMD / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test NVIDIA / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:31 +08:00

566 lines
20 KiB
Python

# Copyright (c) 2026 LightSeek Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import logging
import torch
import torch.distributed as dist
from tokenspeed_kernel.ops.gemm.fp8_utils import (
create_per_token_group_quant_fp8_output_scale,
)
from tokenspeed_kernel.platform import current_platform
from tokenspeed_kernel.registry import ErrorClass, error_fn
logger = logging.getLogger(__name__)
__all__ = [
"AllReduceFusionPattern",
"allgather_dual_rmsnorm",
"allreduce_residual_rmsnorm",
"minimax_allreduce_rms_qk",
"reducescatter_residual_rmsnorm",
"trtllm_allreduce_fusion",
"trtllm_create_ipc_workspace_for_all_reduce_fusion",
"trtllm_create_ipc_workspace_for_minimax",
]
platform = current_platform()
AllReduceFusionPattern = ErrorClass
allgather_dual_rmsnorm = error_fn
allreduce_residual_rmsnorm = error_fn
minimax_allreduce_rms_qk = error_fn
reducescatter_residual_rmsnorm = error_fn
trtllm_allreduce_fusion = error_fn
trtllm_create_ipc_workspace_for_all_reduce_fusion = error_fn
trtllm_create_ipc_workspace_for_minimax = error_fn
if current_platform().is_nvidia:
from tokenspeed_kernel.thirdparty.cuda.trtllm import (
AllGatherFusionPattern,
AllReduceFusionPattern,
ReduceScatterFusionPattern,
minimax_allreduce_rms_qk,
trtllm_allgather_fusion,
trtllm_allreduce_fusion,
trtllm_create_ipc_workspace_for_all_reduce_fusion,
trtllm_create_ipc_workspace_for_minimax,
trtllm_destroy_ipc_workspace_for_all_reduce_fusion,
trtllm_reducescatter_fusion,
)
_workspace_manager = None
class TrtllmFusionWorkspaceManager:
def __init__(self):
self.workspace_tensor = None
self.ipc_handles = None
self.world_size = None
self.rank = None
self.max_token_num = None
self.hidden_dim = None
self.use_fp32_lamport = None
self.initialized = False
self.group_ranks = (
None # tuple of global ranks this workspace was created for
)
def initialize(
self,
world_size: int,
rank: int,
max_token_num: int,
hidden_dim: int,
group,
use_fp32_lamport: bool = False,
):
"""Initialize workspace"""
if (
self.initialized
and self.world_size == world_size
and self.max_token_num == max_token_num
and self.hidden_dim == hidden_dim
and self.use_fp32_lamport == use_fp32_lamport
):
return
self.cleanup()
# allreduce_fusion, allgather_fusion, reducescatter_fusion all use the same workspace to create entry
self.ipc_handles, self.workspace_tensor = (
trtllm_create_ipc_workspace_for_all_reduce_fusion(
rank,
world_size,
max_token_num,
hidden_dim,
group=group,
use_fp32_lamport=use_fp32_lamport,
)
)
self.world_size = world_size
self.rank = rank
self.max_token_num = max_token_num
self.hidden_dim = hidden_dim
self.use_fp32_lamport = use_fp32_lamport
self.initialized = True
self.group = group
logger.info(
f"TRT-LLM fusion workspace initialized for rank {rank}, "
f"world_size {world_size}, "
f"max_token_num {max_token_num}, "
f"hidden_dim {hidden_dim} "
)
def cleanup(self):
"""Clean up workspace"""
if self.initialized and self.ipc_handles is not None:
try:
trtllm_destroy_ipc_workspace_for_all_reduce_fusion(
self.ipc_handles, group=self.group
)
except Exception as e:
logger.warning(f"Failed to cleanup TRT-LLM fusion workspace: {e}")
finally:
self.workspace_tensor = None
self.ipc_handles = None
self.initialized = False
self.world_size = None
self.rank = None
self.max_token_num = None
self.hidden_dim = None
self.use_fp32_lamport = None
self.group_ranks = None
_workspace_manager = TrtllmFusionWorkspaceManager()
#
# # Reduce-scatter now reuses `_workspace_manager` (allreduce-style IPC workspace).
# This avoids keeping a second, similarly-sized workspace alive.
def ensure_workspace_initialized(
rank: int,
group: dist.ProcessGroup,
max_token_num: int = 2048,
hidden_dim: int = 4096,
use_fp32_lamport: bool = False,
):
world_size = group.size()
if world_size <= 1:
return False
target_max_token_num = max_token_num
target_hidden_dim = hidden_dim
target_use_fp32_lamport = use_fp32_lamport
if (
_workspace_manager.initialized
and _workspace_manager.world_size == world_size
):
if _workspace_manager.max_token_num is not None:
target_max_token_num = max(
_workspace_manager.max_token_num, max_token_num
)
if _workspace_manager.hidden_dim is not None:
target_hidden_dim = max(_workspace_manager.hidden_dim, hidden_dim)
if _workspace_manager.use_fp32_lamport:
target_use_fp32_lamport = True
if (
(not _workspace_manager.initialized)
or (_workspace_manager.world_size != world_size)
or (_workspace_manager.max_token_num != target_max_token_num)
or (_workspace_manager.hidden_dim != target_hidden_dim)
or (_workspace_manager.use_fp32_lamport != target_use_fp32_lamport)
):
logger.info(
"Re/initializing TRT-LLM fusion IPC workspace: "
"world_size=%s rank=%s max_token_num=%s hidden_dim=%s use_fp32_lamport=%s "
"(prev max_token_num=%s hidden_dim=%s use_fp32_lamport=%s)",
world_size,
rank,
target_max_token_num,
target_hidden_dim,
target_use_fp32_lamport,
_workspace_manager.max_token_num,
_workspace_manager.hidden_dim,
_workspace_manager.use_fp32_lamport,
)
_workspace_manager.initialize(
world_size=world_size,
rank=rank,
max_token_num=target_max_token_num,
hidden_dim=target_hidden_dim,
use_fp32_lamport=target_use_fp32_lamport,
group=group,
)
return _workspace_manager.initialized
def get_num_tokens_per_rank(world_size: int, total_tokens_in_group: int) -> list:
token_list_in_group = []
for rank in range(0, world_size):
num_tokens_per_rank = total_tokens_in_group // world_size + (
1 if (rank < total_tokens_in_group % world_size) else 0
)
token_list_in_group.append(num_tokens_per_rank)
return token_list_in_group
def allreduce_residual_rmsnorm(
input_tensor: torch.Tensor,
residual: torch.Tensor,
weight: torch.Tensor,
rank: int,
group: dist.ProcessGroup,
eps: float = 1e-6,
max_token_num: int = 2048,
use_oneshot: bool | None = None,
trigger_completion_at_end: bool = False,
fp32_acc: bool = False,
block_quant_fp8: bool = False,
residual_reduce_scattered: bool = False,
has_partial_norm_out: bool = False,
max_sm_to_use: int | None = None,
launch_with_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor]:
"""
Use TRT-LLM fused allreduce + residual + RMS norm operation.
"""
world_size = group.size()
assert world_size > 1, "Single GPU, no need for allreduce fusion"
assert input_tensor.shape[0] <= max_token_num
if not ensure_workspace_initialized(
rank=rank,
group=group,
max_token_num=max_token_num,
hidden_dim=input_tensor.shape[-1],
use_fp32_lamport=(input_tensor.dtype == torch.float32),
):
raise RuntimeError("TRT-LLM fusion workspace not available")
token_num, hidden_dim = input_tensor.shape
residual_out = torch.empty_like(residual)
norm_out = torch.empty_like(input_tensor)
partial_norm_out = None
pattern_code = None
if has_partial_norm_out:
num_tokens_list = get_num_tokens_per_rank(world_size, input_tensor.shape[0])
partial_num_tokens = num_tokens_list[rank]
partial_norm_out = torch.empty(
(partial_num_tokens, hidden_dim),
dtype=input_tensor.dtype,
device=input_tensor.device,
)
pattern_code = (
AllReduceFusionPattern.kARResidualRMSNormPartialOutFP8BlockWiseQuant
if block_quant_fp8
else AllReduceFusionPattern.kARResidualRMSNormPartialOut
)
else:
pattern_code = (
AllReduceFusionPattern.kARResidualRMSNormFP8BlockWiseQuant
if block_quant_fp8
else AllReduceFusionPattern.kARResidualRMSNorm
)
if block_quant_fp8:
quant_out = torch.empty(
input_tensor.size(),
dtype=torch.float8_e4m3fn,
device=input_tensor.device,
)
out_shape = (*quant_out.shape[:-1], quant_out.shape[-1])
scale_out = create_per_token_group_quant_fp8_output_scale(
x_shape=out_shape,
device=quant_out.device,
group_size=128,
column_major_scales=True,
scale_tma_aligned=True,
scale_ue8m0=False,
)
else:
quant_out = None
scale_out = None
if residual_reduce_scattered or has_partial_norm_out:
use_oneshot = True
trtllm_allreduce_fusion(
allreduce_in=input_tensor,
world_size=world_size,
world_rank=rank,
token_num=token_num,
hidden_dim=hidden_dim,
workspace_ptrs=_workspace_manager.workspace_tensor,
launch_with_pdl=launch_with_pdl,
use_oneshot=use_oneshot,
trigger_completion_at_end=trigger_completion_at_end,
fp32_acc=fp32_acc,
pattern_code=(pattern_code),
allreduce_out=None,
residual_in=residual,
residual_out=residual_out,
norm_out=norm_out,
quant_out=quant_out,
scale_out=scale_out,
rms_gamma=weight,
rms_eps=eps,
scale_factor=None,
layout_code=None,
residual_reduce_scattered=residual_reduce_scattered,
max_sm_to_use=max_sm_to_use,
partial_norm_out=partial_norm_out,
)
if block_quant_fp8:
return quant_out, residual_out, scale_out, partial_norm_out
else:
return norm_out, residual_out, None, partial_norm_out
def reducescatter_residual_rmsnorm(
input_tensor: torch.Tensor,
residual: torch.Tensor,
weight: torch.Tensor,
rank: int,
group: dist.ProcessGroup,
eps: float = 1e-6,
max_token_num: int = 2048,
use_oneshot: bool | None = None,
trigger_completion_at_end: bool = False,
fp32_acc: bool = False,
block_quant_fp8: bool = False,
add_in: torch.Tensor | None = None,
launch_with_pdl: bool = False,
) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor | None]:
"""
Use TRT-LLM fused reducescatter + residual + RMS norm operation.
"""
world_size = group.size()
assert world_size > 1, "Single GPU, no need for reducescatter fusion"
assert input_tensor.shape[0] <= max_token_num
if not ensure_workspace_initialized(
rank=rank,
group=group,
max_token_num=max_token_num,
hidden_dim=input_tensor.shape[-1],
use_fp32_lamport=(input_tensor.dtype == torch.float32),
):
raise RuntimeError("TRT-LLM reduce scatter fusion workspace not available")
token_num, hidden_dim = input_tensor.shape
tokens_per_rank = token_num // world_size
remaining = token_num % world_size
token_count = tokens_per_rank + (1 if rank < remaining else 0)
residual_out = torch.empty(
(token_count, hidden_dim), dtype=residual.dtype, device=residual.device
)
norm_out = torch.empty(
(token_count, hidden_dim),
dtype=input_tensor.dtype,
device=input_tensor.device,
)
if block_quant_fp8:
if add_in is not None:
pattern_code = (
ReduceScatterFusionPattern.kRSAddResidualRMSNormFP8BlockWiseQuant
)
else:
pattern_code = (
ReduceScatterFusionPattern.kRSResidualRMSNormFP8BlockWiseQuant
)
else:
if add_in is not None:
pattern_code = ReduceScatterFusionPattern.kRSAddResidualRMSNorm
else:
pattern_code = ReduceScatterFusionPattern.kRSResidualRMSNorm
if block_quant_fp8:
quant_out = torch.empty(
(token_count, hidden_dim),
dtype=torch.float8_e4m3fn,
device=input_tensor.device,
)
out_shape = (*quant_out.shape[:-1], quant_out.shape[-1])
scale_out = create_per_token_group_quant_fp8_output_scale(
x_shape=out_shape,
device=quant_out.device,
group_size=128,
column_major_scales=True,
scale_tma_aligned=True,
scale_ue8m0=False,
)
else:
quant_out = None
scale_out = None
trtllm_reducescatter_fusion(
reducescatter_in=input_tensor,
world_size=world_size,
world_rank=rank,
token_num=token_num,
hidden_dim=hidden_dim,
workspace_ptrs=_workspace_manager.workspace_tensor,
launch_with_pdl=launch_with_pdl,
trigger_completion_at_end=trigger_completion_at_end,
num_token_current_rank=token_count,
fp32_acc=fp32_acc,
pattern_code=pattern_code,
use_oneshot=use_oneshot,
reducescatter_out=None,
add_in=add_in,
residual_in=residual,
residual_out=residual_out,
norm_out=norm_out,
quant_out=quant_out,
scale_out=scale_out,
rms_gamma=weight,
rms_eps=eps,
scale_factor=None,
layout_code=None,
)
if block_quant_fp8:
return quant_out, residual_out, scale_out
else:
return norm_out, residual_out, None
def allgather_dual_rmsnorm(
qkv: torch.Tensor,
total_num_tokens: int,
weight_q_a: torch.nn.Parameter,
weight_kv_a: torch.nn.Parameter,
rank: int,
group: dist.ProcessGroup,
eps_q: float,
eps_kv: float,
max_token_num: int,
block_quant_fp8: bool = False,
trigger_completion_at_end: bool = False,
fp32_acc: bool = False,
launch_with_pdl: bool = False,
) -> tuple[
torch.Tensor | None,
torch.Tensor | None,
torch.Tensor | None,
torch.Tensor | None,
]:
"""
Use TRT-LLM fused allgather + dual RMS norm + optional FP8 quantization.
"""
world_size = group.size()
assert world_size > 1, "Single GPU, no need for allgather fusion"
num_token_current_rank = qkv.shape[0]
hidden_dim = qkv.shape[1]
if num_token_current_rank > max_token_num:
raise RuntimeError(
f"Token count {num_token_current_rank} exceeds max {max_token_num}"
)
if not ensure_workspace_initialized(
rank=rank,
group=group,
max_token_num=max_token_num,
hidden_dim=hidden_dim,
use_fp32_lamport=(qkv.dtype == torch.float32),
):
raise RuntimeError("TRT-LLM fusion workspace not available")
q_lora_rank = weight_q_a.shape[0]
kv_lora_rank = weight_kv_a.shape[0]
qk_rope_head_dim = hidden_dim - q_lora_rank - kv_lora_rank
num_token_all_group = total_num_tokens
allgather_out = torch.empty(
(num_token_all_group, hidden_dim), dtype=qkv.dtype, device=qkv.device
)
x_norm_out = torch.empty(
(num_token_all_group, q_lora_rank), dtype=qkv.dtype, device=qkv.device
)
# y_norm_out output is on the slice of allgather_out
y_norm_out = allgather_out[..., q_lora_rank : q_lora_rank + kv_lora_rank]
if block_quant_fp8:
block_size = 128
quant_out = torch.empty(
(num_token_all_group, q_lora_rank),
dtype=torch.float8_e4m3fn,
device=qkv.device,
)
out_shape = (*quant_out.shape[:-1], quant_out.shape[-1])
scale_out = create_per_token_group_quant_fp8_output_scale(
x_shape=out_shape,
device=quant_out.device,
group_size=block_size,
column_major_scales=True,
scale_tma_aligned=True,
scale_ue8m0=False,
)
else:
quant_out = None
scale_out = None
pattern_code = (
AllGatherFusionPattern.kAllGatherfusedRMSFP8BlockWiseQuant
if block_quant_fp8
else AllGatherFusionPattern.kAllGatherfusedRMS
)
trtllm_allgather_fusion(
allgather_in=qkv,
world_size=world_size,
world_rank=rank,
hidden_dim=hidden_dim,
workspace_ptrs=_workspace_manager.workspace_tensor,
launch_with_pdl=launch_with_pdl,
trigger_completion_at_end=trigger_completion_at_end,
num_token_current_rank=num_token_current_rank,
allgather_out=allgather_out,
num_token_all_group=num_token_all_group,
pattern_code=pattern_code,
use_oneshot=True,
fp32_acc=fp32_acc,
x_norm_out=x_norm_out,
y_norm_out=y_norm_out,
quant_out=quant_out,
scale_out=scale_out,
x_rms_gamma=weight_q_a,
y_rms_gamma=weight_kv_a,
x_rms_eps=eps_q,
y_rms_eps=eps_kv,
q_lora_rank=q_lora_rank,
kv_lora_rank=kv_lora_rank,
qk_rope_head_dim=qk_rope_head_dim,
)
return (
allgather_out,
quant_out if block_quant_fp8 else x_norm_out,
y_norm_out,
scale_out,
)