Files
wehub-resource-sync b5ecf06f65
Code Format Check / format-check (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:24:32 +08:00

343 lines
17 KiB
C++

#pragma once
#include <nccl.h>
#include <nccl_device.h>
#include <deep_ep/common/compiled.cuh>
#include <deep_ep/common/exception.cuh>
#include "../../jit/compiler.hpp"
#include "../../jit/launch_runtime.hpp"
namespace deep_ep::elastic {
class DispatchRuntime final : public jit::LaunchRuntime<DispatchRuntime> {
public:
struct Args {
// Templated arguments
bool is_scaleup_nvlink;
bool do_cpu_sync;
bool reuse_slot_indices;
int num_notify_warps;
int num_dispatch_warps; // For hybrid dispatch
int num_scaleout_warps, num_forward_warps; // For direct dispatch
int num_scaleout_ranks, num_scaleup_ranks;
int num_hidden_bytes, num_sf_packs;
int num_max_tokens_per_rank;
int num_experts, num_topk, expert_alignment;
int num_qps;
int64_t num_timeout_cycles;
// Parameters
void* x; sf_pack_t* sf; topk_idx_t* topk_idx; float* topk_weights;
topk_idx_t* copied_topk_idx;
int* cumulative_local_expert_recv_stats;
int* psum_num_recv_tokens_per_scaleup_rank;
int* psum_num_recv_tokens_per_expert;
int* num_unaligned_recv_tokens_per_expert;
int* dst_buffer_slot_idx;
int* token_metadata_at_forward;
int num_tokens;
int sf_token_stride, sf_hidden_stride;
ncclDevComm_t nccl_dev_comm;
ncclWindow_t nccl_window;
void* buffer;
void* workspace; void* mapped_host_workspace;
int scaleout_rank_idx, scaleup_rank_idx;
jit::LaunchArgs launch_args;
};
static std::string generate_impl(const Args& args) {
std::string header_name, func_name;
if (args.num_scaleout_ranks == 1) {
header_name = "dispatch";
func_name = fmt::format("dispatch_impl<{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}>",
args.is_scaleup_nvlink,
args.do_cpu_sync,
args.reuse_slot_indices,
args.launch_args.grid_dim.first,
args.num_notify_warps, args.num_dispatch_warps,
args.num_scaleup_ranks,
args.num_hidden_bytes, args.num_sf_packs,
args.num_max_tokens_per_rank,
args.num_experts, args.num_topk, args.expert_alignment,
args.num_qps, args.num_timeout_cycles);
} else {
header_name = "hybrid_dispatch";
func_name = fmt::format("hybrid_dispatch_impl<{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}>",
args.do_cpu_sync,
args.reuse_slot_indices,
args.launch_args.grid_dim.first,
args.num_notify_warps, args.num_scaleout_warps, args.num_forward_warps,
args.num_scaleout_ranks, args.num_scaleup_ranks,
args.num_hidden_bytes, args.num_sf_packs,
args.num_max_tokens_per_rank,
args.num_experts, args.num_topk, args.expert_alignment,
args.num_qps, args.num_timeout_cycles);
}
return fmt::format(R"(
#include <deep_ep/impls/{}.cuh>
using namespace deep_ep::elastic;
static void __instantiate_kernel() {{
auto ptr = reinterpret_cast<void*>(&{});
}}
)", header_name, func_name);
}
static void launch_impl(const jit::KernelHandle& kernel, const jit::LaunchConfigHandle& config, Args args) {
if (args.num_scaleout_ranks == 1) {
EP_CUDA_UNIFIED_CHECK(jit::launch_kernel(
kernel, config,
args.x, args.sf, args.topk_idx, args.topk_weights,
args.copied_topk_idx,
args.cumulative_local_expert_recv_stats,
args.psum_num_recv_tokens_per_scaleup_rank,
args.psum_num_recv_tokens_per_expert,
args.num_unaligned_recv_tokens_per_expert,
args.dst_buffer_slot_idx,
args.num_tokens,
args.sf_token_stride, args.sf_hidden_stride,
args.nccl_dev_comm, args.nccl_window,
args.buffer,
args.workspace, args.mapped_host_workspace,
args.scaleup_rank_idx));
} else {
EP_CUDA_UNIFIED_CHECK(jit::launch_kernel(
kernel, config,
args.x, args.sf, args.topk_idx, args.topk_weights,
args.copied_topk_idx,
args.cumulative_local_expert_recv_stats,
args.psum_num_recv_tokens_per_scaleup_rank,
args.psum_num_recv_tokens_per_expert,
args.num_unaligned_recv_tokens_per_expert,
args.dst_buffer_slot_idx,
args.token_metadata_at_forward,
args.num_tokens,
args.sf_token_stride, args.sf_hidden_stride,
args.nccl_dev_comm, args.nccl_window,
args.buffer,
args.workspace, args.mapped_host_workspace,
args.scaleout_rank_idx, args.scaleup_rank_idx
));
}
}
};
constexpr int kNumNotifyWarps = 4;
static int get_num_notify_smem_bytes(const int& num_ranks, const int& num_experts) {
return math::align(num_ranks + num_experts, kNumNotifyWarps * 32) * sizeof(int);
}
static layout::TokenLayout get_dispatch_token_layout(
const int& hidden, const int& elem_size, const int& num_sf_packs, const int& num_topk) {
return layout::TokenLayout(hidden * elem_size, num_sf_packs * sizeof(sf_pack_t), num_topk, true);
}
static void launch_dispatch(void* x, void* sf,
topk_idx_t* topk_idx, float* topk_weights,
topk_idx_t* copied_topk_idx,
int* cumulative_local_expert_recv_stats,
int* psum_num_recv_tokens_per_scaleup_rank,
int* psum_num_recv_tokens_per_expert,
int* num_unaligned_recv_tokens_per_expert,
int* dst_buffer_slot_idx,
int* token_metadata_at_forward,
const int& num_tokens, const int& num_max_tokens_per_rank,
const int& hidden, const int& elem_size,
const int& num_sf_packs, const int& sf_token_stride, const int& sf_hidden_stride,
const int& num_experts, const int& num_topk, const int& expert_alignment,
const ncclDevComm_t& nccl_dev_comm, const ncclWindow_t& nccl_window,
void* buffer,
void* workspace, void* mapped_host_workspace,
const int& scaleout_rank_idx, const int& scaleup_rank_idx,
const int& num_scaleout_ranks, const int& num_scaleup_ranks,
const bool& is_scaleup_nvlink,
const int& num_sms, const int& num_channels_per_sm,
const int& num_smem_bytes,
const int& num_qps, const int64_t& num_timeout_cycles,
const bool& cached_mode,
const bool& do_cpu_sync,
const at::cuda::CUDAStream& stream) {
// Cached mode does not support expert token counting
if (cached_mode)
EP_HOST_ASSERT(cumulative_local_expert_recv_stats == nullptr);
// Utils
const auto num_ranks = num_scaleout_ranks * num_scaleup_ranks;
// Notify warps
// TODO: why don't we use 4 notify warps?
const int num_notify_warps = cached_mode ? 0 : kNumNotifyWarps;
const bool reuse_slot_indices = cached_mode;
const int num_notify_smem_bytes = cached_mode ? 0 : get_num_notify_smem_bytes(num_ranks, num_experts);
EP_HOST_ASSERT(num_notify_warps % 4 == 0);
// Other warps
int num_dispatch_warps = 0;
int num_scaleout_warps = 0, num_forward_warps = 0;
int num_threads = 0;
// Maximize shared memory utilization
if (num_scaleout_ranks == 1) {
const auto token_layout = get_dispatch_token_layout(hidden, elem_size, num_sf_packs, num_topk);
num_dispatch_warps = std::min<int>(
(num_smem_bytes - num_notify_smem_bytes) / token_layout.get_num_bytes<true>(), 32 - num_notify_warps);
num_threads = (num_notify_warps + num_dispatch_warps) * 32;
} else {
// Hybrid kernels
num_scaleout_warps = num_channels_per_sm;
num_forward_warps = num_channels_per_sm;
num_threads = (num_notify_warps + num_scaleout_warps + num_forward_warps) * 32;
}
// Generate, build and launch
const DispatchRuntime::Args args = {
.is_scaleup_nvlink = is_scaleup_nvlink,
.do_cpu_sync = do_cpu_sync,
.reuse_slot_indices = reuse_slot_indices,
.num_notify_warps = num_notify_warps,
.num_dispatch_warps = num_dispatch_warps,
.num_scaleout_warps = num_scaleout_warps, .num_forward_warps = num_forward_warps,
.num_scaleout_ranks = num_scaleout_ranks, .num_scaleup_ranks = num_scaleup_ranks,
.num_hidden_bytes = hidden * elem_size, .num_sf_packs = num_sf_packs,
.num_max_tokens_per_rank = num_max_tokens_per_rank,
.num_experts = num_experts, .num_topk = num_topk, .expert_alignment = expert_alignment,
.num_qps = num_qps, .num_timeout_cycles = num_timeout_cycles,
.x = x, .sf = static_cast<sf_pack_t*>(sf), .topk_idx = topk_idx, .topk_weights = topk_weights,
.copied_topk_idx = copied_topk_idx,
.cumulative_local_expert_recv_stats = cumulative_local_expert_recv_stats,
.psum_num_recv_tokens_per_scaleup_rank = psum_num_recv_tokens_per_scaleup_rank,
.psum_num_recv_tokens_per_expert = psum_num_recv_tokens_per_expert,
.num_unaligned_recv_tokens_per_expert = num_unaligned_recv_tokens_per_expert,
.dst_buffer_slot_idx = dst_buffer_slot_idx,
.token_metadata_at_forward = token_metadata_at_forward,
.num_tokens = num_tokens,
.sf_token_stride = sf_token_stride, .sf_hidden_stride = sf_hidden_stride,
.nccl_dev_comm = nccl_dev_comm, .nccl_window = nccl_window,
.buffer = buffer,
.workspace = workspace, .mapped_host_workspace = mapped_host_workspace,
.scaleout_rank_idx = scaleout_rank_idx, .scaleup_rank_idx = scaleup_rank_idx,
// NOTES: make cluster dim 2 to overlap with clustered computation kernels
.launch_args = jit::LaunchArgs(num_sms, num_threads, num_smem_bytes, 2 - (num_sms % 2), true)};
const auto code = DispatchRuntime::generate(args);
const auto runtime = jit::compiler->build("dispatch", code);
DispatchRuntime::launch(runtime, args, stream);
}
class DispatchCopyEpilogueRuntime final : public jit::LaunchRuntime<DispatchCopyEpilogueRuntime> {
public:
struct Args {
// Templated arguments
bool do_expand, cached_mode, do_zero_padding;
int num_channels;
int num_warps;
int num_scaleout_ranks, num_scaleup_ranks;
int num_hidden_bytes, num_sf_packs;
int num_max_tokens_per_rank;
int num_experts, num_topk, expert_alignment;
// Parameters
void *buffer, *workspace;
int* psum_num_recv_tokens_per_scaleup_rank;
int* psum_num_recv_tokens_per_expert;
void* recv_x; void* recv_sf;
topk_idx_t* recv_topk_idx; float* recv_topk_weights;
int* recv_src_metadata;
int* channel_linked_list;
int* num_unaligned_recv_tokens_per_expert;
int num_recv_tokens;
int recv_sf_token_stride, recv_sf_hidden_stride;
int scaleout_rank_idx, scaleup_rank_idx;
jit::LaunchArgs launch_args;
};
static std::string generate_impl(const Args& args) {
return fmt::format(R"(
#include <deep_ep/impls/dispatch_copy_epilogue.cuh>
using namespace deep_ep::elastic;
static void __instantiate_kernel() {{
auto ptr = reinterpret_cast<void*>(&dispatch_copy_epilogue_impl<{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}>);
}}
)",
args.do_expand, args.cached_mode, args.do_zero_padding,
args.launch_args.grid_dim.first, args.num_channels, args.num_warps,
args.num_scaleout_ranks, args.num_scaleup_ranks,
args.num_hidden_bytes, args.num_sf_packs,
args.num_max_tokens_per_rank,
args.num_experts, args.num_topk, args.expert_alignment);
}
static void launch_impl(const jit::KernelHandle& kernel, const jit::LaunchConfigHandle& config, Args args) {
EP_CUDA_UNIFIED_CHECK(jit::launch_kernel(kernel, config,
args.buffer, args.workspace,
args.psum_num_recv_tokens_per_scaleup_rank,
args.psum_num_recv_tokens_per_expert,
args.recv_x, args.recv_sf, args.recv_topk_idx, args.recv_topk_weights,
args.recv_src_metadata,
args.channel_linked_list,
args.num_unaligned_recv_tokens_per_expert,
args.num_recv_tokens,
args.recv_sf_token_stride, args.recv_sf_hidden_stride,
args.scaleout_rank_idx, args.scaleup_rank_idx));
}
};
static void launch_dispatch_copy_epilogue(void* buffer, void* workspace,
int* psum_num_recv_tokens_per_scaleup_rank,
int* psum_num_recv_tokens_per_expert,
void* recv_x, void* recv_sf,
topk_idx_t* recv_topk_idx, float* recv_topk_weights,
int* recv_src_metadata,
int* channel_linked_list,
int* num_unaligned_recv_tokens_per_expert,
const int& num_recv_tokens, const int& num_max_tokens_per_rank,
const int& num_hidden_bytes,
const int& num_sf_packs, const int& recv_sf_token_stride, const int& recv_sf_hidden_stride,
const int& num_experts, const int& num_topk, const int& expert_alignment,
const int& scaleout_rank_idx, const int& scaleup_rank_idx,
const int& num_scaleout_ranks, const int& num_scaleup_ranks,
const int& num_sms, const int& num_smem_bytes,
const int& num_channels,
const bool& do_expand, const bool& cached_mode,
const bool& do_zero_padding,
const at::cuda::CUDAStream& stream) {
// Maximize shared memory utilization
const auto token_layout = layout::TokenLayout(num_hidden_bytes, num_sf_packs * sizeof(sf_pack_t), num_topk, true);
const auto num_warps = std::min(num_smem_bytes / token_layout.get_num_bytes<true>(), 32);
const auto num_threads = num_warps * 32;
// Generate, build and launch
const DispatchCopyEpilogueRuntime::Args args = {
.do_expand = do_expand, .cached_mode = cached_mode, .do_zero_padding = do_zero_padding,
.num_channels = num_channels, .num_warps = num_warps,
.num_scaleout_ranks = num_scaleout_ranks, .num_scaleup_ranks = num_scaleup_ranks,
.num_hidden_bytes = num_hidden_bytes, .num_sf_packs = num_sf_packs,
.num_max_tokens_per_rank = num_max_tokens_per_rank,
.num_experts = num_experts, .num_topk = num_topk, .expert_alignment = expert_alignment,
.buffer = buffer, .workspace = workspace,
.psum_num_recv_tokens_per_scaleup_rank = psum_num_recv_tokens_per_scaleup_rank,
.psum_num_recv_tokens_per_expert = psum_num_recv_tokens_per_expert,
.recv_x = recv_x, .recv_sf = recv_sf,
.recv_topk_idx = recv_topk_idx, .recv_topk_weights = recv_topk_weights,
.recv_src_metadata = recv_src_metadata,
.channel_linked_list = channel_linked_list,
.num_unaligned_recv_tokens_per_expert = num_unaligned_recv_tokens_per_expert,
.num_recv_tokens = num_recv_tokens,
.recv_sf_token_stride = recv_sf_token_stride, .recv_sf_hidden_stride = recv_sf_hidden_stride,
.scaleout_rank_idx = scaleout_rank_idx, .scaleup_rank_idx = scaleup_rank_idx,
.launch_args = jit::LaunchArgs(num_sms, num_threads, num_smem_bytes, 1, false, true)};
const auto code = DispatchCopyEpilogueRuntime::generate(args);
const auto runtime = jit::compiler->build("dispatch_copy_epilogue", code);
DispatchCopyEpilogueRuntime::launch(runtime, args, stream);
}
} // namespace deep_ep::elastic