从 DeepEP 到 Mega MoE:MoE Runtime 演进分析
基于 DeepGEMM 源码的实证分析,验证博客中提出的演进叙事
1. 概述
博客《Understanding GPU Microarchitecture from a Workload Perspective (3): DeepEP's First Principles》第 9 节提出了 MoE Runtime 的演进路径:
DeepEP: Communication + Data Movement Runtime
↓
Mega MoE: Communication + Compute Fusion Runtime
↓
DeepEP + DeepGEMM + Fusion Kernel → Unified MoE Dataflow Runtime
本文档通过分析 DeepGEMM 中 Mega MoE 的实际实现(Blackwell SM100, FP8×FP4),验证这一演进叙事。
2. 演进时间线
timeline
title MoE Runtime 演进路径
2024 : DeepEP v1
: All-to-All 通信库
: Dispatch/Combine 分离
: 通信与计算解耦
2025 : DeepEP v2 (Low-Latency Kernel)
: 三阶段流水线
: Warp Specialization
: NVLink + RDMA 统一
2025 : DeepGEMM Mega MoE
: 通信+计算融合
: 单 Kernel 完成全部 MoE 计算
: Symmetric Memory (NVLink)
2026 : Unified MoE Dataflow Runtime (愿景)
: DeepEP + DeepGEMM + Fusion Kernel
: 统一数据流执行
3. Mega MoE 融合了什么?
3.1 完整操作清单
Mega MoE 在单个 CUDA Kernel 中融合了以下全部操作:
| 阶段 | 操作 | 代码位置 | 说明 |
|---|---|---|---|
| Token Routing | 读取 topk_idx/topk_weights | read_topk_idx lambda |
解析 Router 输出的专家映射 |
| Dispatch (通信) | 跨 Rank 拉取 Token 数据 | pull_buffer + TMA load |
NVLink/Symmetric Memory 远程读取 |
| Linear1 (Gate/Up) | FP8×FP4 GEMM | SM100_MMA_MXF8F6F4_2x1SM_SS::fma |
UMMA 指令,2x1SM 多播 |
| SwiGLU Activation | silu(gate) × up × weight | L1 Epilogue | TMEM → Register → 激活 → FP8 重量化 |
| Linear2 (Down) | FP8×FP4 GEMM | SM100_MMA_MXF8F6F4_2x1SM_SS::fma |
UMMA 指令,L1 输出直接作为 L2 输入 |
| Combine (通信) | 跨 Rank 写回 + Top-K Reduce | combine_token_buffer + TMA store |
NVLink 远程写入 + 累加 |
3.2 融合 Kernel 的 Warp 角色分配
graph TB
subgraph "Mega MoE Kernel (Single CUDA Kernel)"
W0["Warp 0..N-1<br/>Dispatch Warps<br/>Token 路由 + NVLink Pull"]
WN["Warp N<br/>TMA Load (Tokens + SFA)"]
WN1["Warp N+1<br/>TMA Load (Weights + SFB)"]
WN2["Warp N+2<br/>MMA Issue<br/>UMMA 指令发射"]
WE["Warp N+3..End<br/>Epilogue Warps<br/>SwiGLU + FP8 Cast<br/>+ Combine Write-back"]
end
W0 -->|"Token 就绪通知"| WN
WN -->|"Smem A 就绪"| WN2
WN1 -->|"Smem B 就绪"| WN2
WN2 -->|"TMEM Accumulator"| WE
对应代码(sm100_fp8_fp4_mega_moe.cuh):
// 不同 warp 角色划分
if (warp_idx < kNumDispatchWarps) {
// Dispatch warps: Token 路由 + 跨 Rank 拉取
...
} else if (warp_idx == kNumDispatchWarps) {
// GEMM TMA load warp for tokens with SFA
...
} else if (warp_idx == kNumDispatchWarps + 1) {
// GEMM TMA load warp for weights with SF
...
} else if (warp_idx == kNumDispatchWarps + 2) {
// GEMM MMA issue warp (UMMA 指令发射)
...
} else if (warp_idx >= kNumDispatchWarps + kNumMMANonEpilogueWarps) {
// Epilogue warps: SwiGLU + Combine
...
}
4. 什么没有被融合?
4.1 仍在 Kernel 外部的操作
| 操作 | 位置 | 原因 |
|---|---|---|
| Router (Top-K 选择) | Python 前置步骤 | 产生 topk_idx/topk_weights |
| 权重 FP4 转换 | transform_weights_for_mega_moe() |
一次性预处理 |
| 输入 FP8 量化 | per_token_cast_to_fp8() |
数据预处理 |
| 最终输出写回 | TMA store to y |
Kernel 末尾,但非核心计算 |
4.2 权重预处理代码
# deep_gemm/mega/__init__.py
def transform_weights_for_mega_moe(l1_weights, l2_weights):
# L1: interleave gate/up, then transpose SF for UTCCP
l1_interleaved = _interleave_l1_weights(l1_weights)
l1_weights = (l1_interleaved[0], _transpose_sf_for_utccp(l1_interleaved[1]))
# L2: only transpose SF for UTCCP
l2_weights = (l2_weights[0], _transpose_sf_for_utccp(l2_weights[1]))
return l1_weights, l2_weights
5. 通信+计算融合的实现路径
5.1 DeepEP 模式:分离式
[Router] → [DeepEP Dispatch] → [Expert Buffer] → [GEMM] → [DeepEP Combine] → [Output]
↑ ↑ ↑
NVLink/RDMA HBM 写入 NVLink/RDMA
5.2 Mega MoE 模式:融合式
[Router] → [Mega MoE Kernel] → [Output]
│
├─ Dispatch Warps: NVLink Pull → Smem → L1 Buffer (HBM local)
├─ MMA Warps: L1 Buffer → UMMA → TMEM
├─ Epilogue: TMEM → SwiGLU → FP8 Cast → L2 Buffer (HBM local)
├─ MMA Warps: L2 Buffer → UMMA → TMEM
└─ Epilogue: TMEM → NVLink Write-back → Combine Reduce → Output
5.3 关键代码:Dispatch 阶段
// sm100_fp8_fp4_mega_moe.cuh - Dispatch Warps
// 1. 统计每个 Expert 的 Token 数量
read_topk_idx([&](const uint32_t& token_topk_idx, const int& expert_idx) {
atomicAdd_block(smem_expert_count + expert_idx, 1);
});
// 2. 计算全局偏移(跨 Rank 累加)
for (uint32_t i = thread_idx; i < kNumExperts; i += kNumDispatchThreads) {
const uint64_t send_value = (1ull << 32) | static_cast<uint64_t>(smem_expert_count[i]);
smem_expert_count[i] = static_cast<uint32_t>(
ptx::atomic_add(workspace.get_expert_send_count_ptr(i), send_value));
}
// 3. 写入源 Token 索引到 Symmetric Buffer(跨 Rank 可见)
*sym_buffer.map(dst_ptr, dst_rank_idx) = token_topk_idx;
// 4. 从远程 Rank 拉取 Token 数据(TMA Load via NVLink)
ptx::tma_load_1d(
pull_buffer.get_base_ptr(),
sym_buffer.map(input_token_buffer.get_data_buffer(src_token_idx).get_base_ptr(),
current_rank_in_expert_idx),
pull_mbarrier, kHidden);
5.4 关键代码:Combine 阶段
// sm100_fp8_fp4_mega_moe.cuh - Combine (Epilogue Warps)
// 1. 从 combine_token_buffer 读取各 Top-K 专家结果
const auto src_ptr = math::advance_ptr<uint8_t>(
combine_token_buffer.get_rank_buffer(slot_idx)
.get_data_buffer(token_idx).get_base_ptr(),
chunk_byte_offset);
ptx::tma_load_1d(combine_load_buffer[i], src_ptr, combine_load_barriers[i], kNumChunkBytes);
// 2. 累加所有 Top-K 贡献
float2 reduced[kNumUint4PerLane * kNumElemsPerUint4] = {};
while (do_reduce) {
do_reduce = move_mask_and_load(load_stage_idx ^ 1);
combine_load_barriers[load_stage_idx]->wait(combine_phase);
for (uint32_t j = 0; j < kNumUint4PerLane; ++ j) {
const auto uint4_values = combine_load_buffer[load_stage_idx][j * 32 + lane_idx];
const auto bf16_values = reinterpret_cast<const nv_bfloat162*>(&uint4_values);
for (uint32_t l = 0; l < kNumElemsPerUint4; ++ l)
ptx::accumulate(reduced[j * kNumElemsPerUint4 + l], bf16_values[l]);
}
}
// 3. 写回最终输出
ptx::tma_store_1d(
math::advance_ptr(y, static_cast<uint64_t>(token_idx) * kNumHiddenBytes + chunk_byte_offset),
combine_store_buffer, kNumChunkBytes);
6. Linear1 / SwiGLU / Linear2 的具体位置
6.1 Linear1 (Gate/Up Projection)
位置: sm100_fp8_fp4_mega_moe.cuh 第 763-865 行
// MMA Issue Warp - Linear1 Phase
if (block_phase == sched::BlockPhase::Linear1) {
// 等待 Token 数据到达
const auto ptr = workspace.get_l1_arrival_count_ptr(pool_block_idx);
while (ptx::ld_acq(ptr) != expected);
// 发射 UMMA 指令
ptx::SM100_MMA_MXF8F6F4_2x1SM_SS::fma(
b_desc, a_desc, accum_stage_idx * UMMA_N,
k_block_idx > 0 or k > 0, runtime_instr_desc,
kTmemStartColOfSFB, kTmemStartColOfSFA);
}
6.2 SwiGLU Activation
位置: sm100_fp8_fp4_mega_moe.cuh 第 931-1012 行
// L1 Epilogue: SwiGLU in-place with weight application
if (block_phase == sched::BlockPhase::Linear1) {
// 从 TMEM 加载 MMA 结果
cute::SM100_TMEM_LOAD_16dp256b1x::copy(tmem_addr, values[0], ..., values[7]);
// 应用 SwiGLU: silu(gate) * up * weight
auto gate = __bfloat1622float2(bf16_gate);
auto neg_gate_exp = make_float2(expf(-gate.x), expf(-gate.y));
const auto denom = __fadd2_rn({1.0f, 1.0f}, neg_gate_exp);
gate = __fmul2_rn(gate, {math::fast_rcp(denom.x), math::fast_rcp(denom.y)});
const auto up = __bfloat1622float2(bf16_up);
swiglu_values[i * 2 + k] = __fmul2_rn(__fmul2_rn(gate, up), weights);
// 重量化为 FP8 并写回 Shared Memory
const auto fp8x4_values = __nv_fp8x4_e4m3(make_float4(upper.x, upper.y, lower.x, lower.y));
ptx::SM100_U8x4_STSM_T<__nv_fp8x4_e4m3>::copy(fp8x4_values, smem_ptr);
}
6.3 Linear2 (Down Projection)
位置: sm100_fp8_fp4_mega_moe.cuh 第 1108-1208 行
// L2 Epilogue: BF16 output write-back via NVLink
} else { // block_phase == BlockPhase::Linear2
// 从 TMEM 加载 L2 MMA 结果
cute::SM100_TMEM_LOAD_16dp256b1x::copy(tmem_addr, values[0], ..., values[7]);
// 写入 Shared Memory (BF16)
ptx::SM90_U32x4_STSM_T<uint32_t>::copy(
math::cast_into_bf16_and_pack(values[0], values[1]), ...);
// 通过 NVLink 写入远程 Rank 的 Combine Buffer
const auto dst_token = combine_token_buffer.get_rank_buffer(dst_topk_idx)
.get_data_buffer(dst_token_idx);
*sym_buffer.map(dst_ptr, dst_rank_idx) = packed;
}
7. Dispatch/Combine 在 Kernel 内 vs DeepEP 分离式
7.1 对比表
| 维度 | DeepEP | Mega MoE |
|---|---|---|
| 执行单元 | 独立 Kernel | 同一 Kernel 内不同 Warp |
| 通信方式 | NVLink/RDMA 显式 API | Symmetric Memory + TMA |
| 数据缓冲 | Expert Buffer (HBM) | L1/L2 Buffer (HBM local) |
| 同步机制 | 全局 Kernel 完成 | 内部 Barrier (mbarrier) |
| 中间数据 | 写回 HBM 再读取 | 留在 Smem/TMEM 流水线内 |
7.2 性能优势:消除中间内存写入
graph LR
subgraph "DeepEP (分离)"
D1["Dispatch"] -->|"HBM Write"| B1["Expert Buffer"]
B1 -->|"HBM Read"| G1["GEMM"]
G1 -->|"HBM Write"| B2["Output Buffer"]
B2 -->|"HBM Read"| C1["Combine"]
end
subgraph "Mega MoE (融合)"
D2["Dispatch"] -->|"Smem/TMEM"| G2["Linear1"]
G2 -->|"Register"| S2["SwiGLU"]
S2 -->|"Smem/TMEM"| G3["Linear2"]
G3 -->|"Smem/NVLink"| C2["Combine"]
end
关键收益:
1. L1 → L2 数据流: SwiGLU 输出直接留在 Smem,无需写回 HBM
2. Token 数据: Dispatch 拉取直接写入 L1 Buffer,GEMM TMA 直接读取
3. Combine 写回: L2 输出通过 NVLink 直接写入远程 Combine Buffer
8. 性能收益分析
8.1 理论收益
| 优化点 | 节省 | 原因 |
|---|---|---|
| Kernel Launch Overhead | ~10-20μs | 单 Kernel vs 多 Kernel |
| HBM Bandwidth | 消除中间写回 | L1→L2 数据流不经过 HBM |
| Memory Capacity | 减少 Buffer 占用 | 无需完整 Expert Buffer |
| 通信-计算重叠 | 更细粒度 | Warp 级流水线 |
8.2 测试代码中的性能计算
# tests/test_mega_moe.py
# TFLOPS: 3 matmuls (L1 left, L1 right, L2), each 2 * M * N * K
tflops = safe_div(2 * num_recv_tokens * (hidden * intermediate_hidden * 3) / 1e12, t_fused)
# HBM bytes: weights (FP4 packed = 0.5 bytes) + activations (FP8 = 1 byte) + output (BF16 = 2 bytes)
num_hbm_bytes = (
num_experts_per_rank * intermediate_hidden * 2 * hidden // 2 + # L1 weights (FP4)
num_experts_per_rank * hidden * intermediate_hidden // 2 + # L2 weights (FP4)
num_recv_tokens * hidden + # L1 acts read (FP8)
num_recv_tokens * intermediate_hidden + # L1 output write (FP8)
num_recv_tokens * intermediate_hidden + # L2 acts read (FP8)
num_recv_tokens * hidden * 2 # L2 output write (BF16)
)
# NVLink bytes: dispatch pull + combine write-back
num_nvlink_bytes = num_recv_tokens * hidden * 3
9. Mega MoE 是 DeepEP 的替代还是补充?
9.1 结论:互补关系
| 场景 | DeepEP | Mega MoE |
|---|---|---|
| 节点内 (Intra-node) | ✅ 支持 | ✅ 优化 (Symmetric Memory) |
| 跨节点 (Inter-node) | ✅ RDMA | ❌ 仅 NVLink |
| 训练/预填充 | ✅ Normal Kernel | ✅ 单 Kernel |
| 解码 (Decode) | ✅ Low-Latency Kernel | ⚠️ 需适配 |
| 硬件要求 | SM90+ | SM100+ (Blackwell) |
9.2 代码证据:测试中的 Baseline 对比
# tests/test_mega_moe.py
# Non-overlapped baseline: EP dispatch + GEMM + EP combine
def run_baseline():
recv_x, _, recv_topk_weights, handle, _ = ep_buffer.dispatch(...)
deep_gemm.m_grouped_fp8_fp4_gemm_nt_contiguous(recv_x, l1_weights, l1_y, ...)
l1_y = tilelang_ops.swiglu_apply_weight_to_fp8(...)
deep_gemm.m_grouped_fp8_fp4_gemm_nt_contiguous(l1_y, l2_weights, l2_y, ...)
return ep_buffer.combine(l2_y, handle=handle)[0]
# Run fused mega MoE
def run_fused():
deep_gemm.fp8_fp4_mega_moe(y, transformed_l1_weights, transformed_l2_weights, buffer, ...)
return y
关键发现: 测试代码将 DeepEP + DeepGEMM 分离执行作为 baseline,Mega MoE 作为融合版本对比。
10. "Unified MoE Dataflow Runtime" 是什么?
10.1 博客原文
Further evolution: DeepEP + DeepGEMM + Fusion Kernel → Unified MoE Dataflow Runtime
10.2 分析
Mega MoE 是"Unified MoE Dataflow Runtime"的第一步,但不是最终形态:
| 组件 | 当前状态 | 在 Mega MoE 中 |
|---|---|---|
| DeepEP | 独立库 | ❌ 未集成(跨节点 RDMA) |
| DeepGEMM | FP8×FP4 GEMM | ✅ 融合(UMMA 指令) |
| Fusion Kernel | Mega MoE Kernel | ✅ 已实现 |
10.3 演进路径
Phase 1 (当前): Mega MoE
├── 节点内 NVLink 通信 + 计算融合
├── 单 Kernel 完成 MoE 全流水线
└── 依赖 Symmetric Memory (PyTorch)
Phase 2 (愿景): Unified MoE Dataflow Runtime
├── 集成 DeepEP 的跨节点 RDMA 能力
├── 统一调度器(通信 + 计算 + 内存)
├── 自适应选择通信路径(NVLink vs RDMA)
└── 全局最优的 Dataflow 执行
11. 核心发现总结
11.1 博客叙事验证
| 博客声明 | 代码验证 | 结论 |
|---|---|---|
| "Mega MoE fuses Token Routing → Dispatch → Linear1 → Activation → Linear2 → Combine" | ✅ 完全一致 | 准确 |
| "DeepEP: MoE Data Movement Runtime" | ✅ DeepEP 专注数据搬运 | 准确 |
| "Mega MoE: Communication + Compute Fusion Runtime" | ✅ 单 Kernel 融合 | 准确 |
| "System trends are further fusing Communication + Compute" | ✅ 代码体现 | 准确 |
| "DeepEP + DeepGEMM + Fusion Kernel → Unified MoE Dataflow Runtime" | ⚠️ 部分实现 | 愿景 |
11.2 关键洞察
- Mega MoE 是"单 Kernel MoE": 将 MoE 层的全部计算+通信封装到一个 CUDA Kernel
- Warp Specialization 延续: 类似 DeepEP,Mega MoE 使用不同 Warp 处理不同阶段
- Symmetric Memory 是关键: 利用 PyTorch 的
torch.distributed._symmetric_memory实现跨 Rank 直接访问 - TMEM 加速: 利用 Blackwell 的 Tensor Memory 实现 MMA 累加器与 Epilogue 的高效交互
- FP8→SwiGLU→FP8 流水线: 在 Register 中完成激活和重量化,避免额外 HBM 访问
12. 代码文件索引
| 文件 | 作用 |
|---|---|
deep_gemm/mega/__init__.py |
Python API 入口 |
csrc/apis/mega.hpp |
C++ API 和 Buffer 管理 |
csrc/jit_kernels/impls/sm100_fp8_fp4_mega_moe.hpp |
JIT Kernel 实例化 |
deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe.cuh |
CUDA Kernel 核心实现 |
deep_gemm/include/deep_gemm/scheduler/mega_moe.cuh |
任务调度器 |
tests/test_mega_moe.py |
正确性测试和性能基准 |
分析日期: 2026-07-30
代码版本: DeepGEMM (Blackwell SM100 FP8×FP4 Mega MoE)
博客参考: 《Understanding GPU Microarchitecture from a Workload Perspective (3): DeepEP's First Principles》Section 9