FusedDeepMoE 算子家族深度分析报告

CAM 皇冠上的明珠 — 三变体架构全景解剖 分支: remotes/origin/cam_feature | 分析日期: 2026-07-21


目录

  1. 家族概览与设计哲学
  2. 三变体架构对比总览
  3. Base 变体 (fused_deep_moe) — 完整流程深度分析
  4. W4A8 变体 (fused_deep_moe_w4a8) — INT4 量化融合
  5. FWK 变体 (fused_deep_moe_fwk) — 框架原生范式
  6. 三条执行路径的 cam_feature 演进
  7. raw_distributed 子模块 — 通信原语解剖
  8. GEMM/Epilogue 子模块 — 计算内核
  9. SHMEM 集成机制
  10. 关键数据结构与内存布局

1. 家族概览与设计哲学

FusedDeepMoE 是 CAM (Communication Acceleration for Matrix) 中最复杂的算子家族,将 MoE Decode 阶段的 Dispatch → GMM1 → SwiGLU → GMM2 → Combine 五阶段完整流水线融合为单一 kernel launch。

核心动机:消除中间数据的 Global Memory 往返。 标准小算子组合中,中间数据 X1、SwigluOut、X2 需要至少 8 次 GM 访问;融合后全部在片上 workspace 中流转。

三个变体服务不同的部署场景:

维度 Base (fused_deep_moe) W4A8 (fused_deep_moe_w4a8) FWK (fused_deep_moe_fwk)
定位 通用 EP 融合 MoE INT4/INT8 混合量化 框架原生 + OPX 流水线
Weight 类型 INT8 INT4 (int4b_t) INT8
requires_shmem true false false
创建时间 2025-07-19 2026-06-29 2026-01-20
共享专家 可选 (share_gmm1/2_weight) 可选 + Bias 支持 原生 sharedExpertNum/RankNum
模板参数 W1ScaleType, W2ScaleType 同 Base 仅 ExpandXType
GMM1_L1K/L0K 512 / 128 1024 / 256 512 / 128
Bias 输入 无 gmm1/2_bias + share_bias 无
通信机制 SHMEM + HCCL Window HCCL Window (MC2) HCCL Window + OPX LibOps

2. 三变体架构对比总览

2.1 统一执行模型

三个变体共享相同的五阶段融合架构,但通信与量化路径不同:

┌─────────────────────────────────────────────────────────────────────┐
│                    FusedDeepMoE 统一执行流程                         │
│                                                                     │
│  ┌──────────┐   ┌──────────┐   ┌─────────┐   ┌────────┐   ┌──────┐ │
│  │ Dispatch │──▶│   GMM1   │──▶│ SwiGLU  │──▶│  GMM2  │──▶│Combine│ │
│  │ (AIV)    │   │ (AIC+AIV)│   │(Epilogue│   │(AIC+   │   │(AIV)  │ │
│  │          │   │          │   │ fused)  │   │ AIV)   │   │       │ │
│  └──────────┘   └──────────┘   └─────────┘   └────────┘   └──────┘ │
│       │              │              │              │           │     │
│  AlltoAll      PerTokenDeq   PerTokenDeq    PerTokenDeq  AlltoAll  │
│  Send          + Swiglu      + Quant        + Combine    Recv     │
│  + Quant       + Quant                                               │
│                                                                     │
│  ─────── 中间数据全部在片上 workspace 流转,不访问 GM ───────         │
└─────────────────────────────────────────────────────────────────────┘

2.2 模板体系对比

Base 变体 (fused_deep_moe.h):

// 完整的 6 参数模板,支持灵活的 Scale 类型
template <typename ExpandXType, typename W1ScaleType, typename W2ScaleType,
          typename ExpandIdxType, bool IsNeedReduceScatter, uint32_t EXEC_FLAG>
class FusedDeepMoe { ... };
// 实例化: FusedDeepMoe<DTYPE_X, DTYPE_GMM1_WEIGHT_SCALE, DTYPE_GMM2_WEIGHT_SCALE, int32_t, false, TILING_KEY_VAR>

FWK 变体 (fused_deep_moe_fwk.h):

// 简化模板:去掉 Scale 类型参数,EXEC_FLAG 提升为第一参数
template <typename ExpandXType, typename ExpandIdxType,
          bool IsNeedReduceScatter, uint32_t EXEC_FLAG>
class FusedDeepMoeFwk { ... };
// 实例化: FusedDeepMoeFwk<DTYPE_X, int32_t, false, TILING_KEY_VAR>

W4A8 变体: 同 Base 的 6 参数模板,但内部类型使用 AscendC::int4b_t。

2.3 EXEC_FLAG 位定义

三个变体共享大部分标志位,但存在关键差异:

标志位 Base W4A8 FWK 含义
EXEC_FLAG_DEEP_FUSE (bit 0) ✅ ✅ ✅ 深度融合(Dispatch 在 GMM Kernel 内)
EXEC_FLAG_TENSOR_LIST (bit 1) ✅ ❌ ✅ 权重为 TensorList
EXEC_FLAG_X_ACTIVE_MASK (bit 2) ✅ ❌ ❌ Token 激活掩码
EXEC_FLAG_SHARED_EXPERT (bit 3) ✅ ✅ ❌ 共享专家
EXEC_FLAG_SMOOTH_QUANT (bit 4) ✅ ❌ ❌ 平滑量化
EXEC_FLAG_ZERO_BUFFER (bit 5) ✅ ❌ ❌ 零缓冲区(Base 独有)

关键差异: Base 有 EXEC_FLAG_ZERO_BUFFER(SHMEM 双缓冲清零),W4A8/FWK 无此标志。FWK 无 SHARED_EXPERT(共享专家通过 sharedExpertNum 原生集成)。


3. Base 变体 (fused_deep_moe) — 完整流程深度分析

源文件位置: src/cam/comm_operator/ascend_kernels/fused_deep_moe/

3.1 文件结构

fused_deep_moe/
├── op_kernel/
│   ├── fused_deep_moe.{h,cpp}          ← 主 kernel 入口 + FusedDeepMoe 类
│   ├── fused_deep_moe_base.h           ← 模板宏定义 + 通信组结构
│   ├── fused_deep_moe_tiling.{h,cpp}   ← TilingData 定义 + 编译期常量
│   ├── fused_deep_moe/                 ← 子模块目录
│   │   ├── gemm/                       ← GEMM block_mmad, kernel
│   │   ├── epilogue/                   ← Epilogue block, tile, policy
│   │   └── raw_distributed/            ← dispatch/combine 通信原语
│   └── cam_moe_distribute_*.h          ← 兼容性别名(实际指向子模块)
├── op_host/
│   └── fused_deep_moe_infer.cpp        ← 仅 InferShape/InferDataType
└── op_api/
    └── aclnn_fused_deep_moe.{h,cpp}    ← aclnn 接口封装

注意: Base 变体的 host 侧只有 infer.cpp(无 tiling.cpp),说明其 tiling 参数全部在 kernel 侧通过 constexpr 计算,或依赖 MC2 框架的默认 tiling。

3.2 主 Kernel 入口

// fused_deep_moe.cpp
extern "C" __global__ __aicore__ void fused_deep_moe(...) {
    icache_preload(8);
    REGISTER_TILING_DEFAULT(FusedDeepMoeTilingData);
    KERNEL_TASK_TYPE_DEFAULT(KERNEL_TYPE_MIX_AIC_1_2);  // 1C2V 混合调度
    GET_TILING_DATA(tiling_data, tiling);
    // 64 个 tiling key 分支(编译期展开)
    CALL_FUSED_DEEP_MOE_IF_TILINGKEY(0)
    CALL_FUSED_DEEP_MOE_ELIF_TILINGKEY(1)
    // ... 直至 key 63
}

关键设计: 64 个 tiling key 通过宏展开为编译期 if constexpr 链,每个 key 对应不同的 EXEC_FLAG 组合。这允许编译器为每种配置生成特化代码。

3.3 FusedDeepMoe::Init — 参数初始化

Init 方法(fused_deep_moe.h L352-412)完成:

  1. GM 地址绑定: 所有输入/输出/权重的 Global Memory 指针
  2. 维度推导: - maxTokenNum_ = maxBs * epRankSize * min(topK, moeExpertNumPerRank) — 单 rank 需处理的最大 token 数 - gmm2InputDim_ = gmm1OutputDim_ / 2 — SwiGLU 将隐藏维度减半 - shareGmm2InputDim_ = shareGmm1OutputDim_ / 2
  3. SHMEM workspace 指针: shmemWorkspaceGM_ 从 tiling 数据的 shmemWorkspacePtr 获取
  4. statusDataSpace 偏移计算: 用于 cross-rank 状态同步的多缓冲区布局

3.4 FusedDeepMoe::Process — 五阶段融合主流程

Process() 是整个算子的核心(fused_deep_moe.h L414-558),分两大阶段:

阶段 A: Problem Shape 与 Workspace 布局

GemmCoord gmm1ProblemShape{maxTokenNum_, gmm1OutputDim_, tokenHiddenSize_};  // [M, N, K]
GemmCoord gmm2ProblemShape{maxTokenNum_, gmm2OutputDim_, gmm2InputDim_};

Workspace 内存布局(全部在 GM 上,但中间数据通过 SHMEM 在片上流转):

shmemWorkspaceGM_ (Base 独有,SHMEM 双缓冲):
├── gmShareX1 / gmX1          — GMM1 输入 token (int8)
├── gmShareX2 / gmX2          — GMM2 输入 token (int8)
├── gmTokenFlag               — token 到达标志
├── gmAllExpertTokenNums      — 全局专家 token 计数
└── gmCombineSend             — Combine 发送缓冲

workspaceGM_ (普通 GM workspace):
├── gmCVSwap                  — Cube 计算 workspace (blockDim * L1M*L1N * STAGES * int32)
├── gmShareSwigluOut/gmSwigluOut — SwiGLU 输出 (float)
├── gmGroupList               — 专家分组列表
├── gmExpandIdx               — 展开索引
├── gmEpSendCount             — EP 发送计数
├── gmResvered                — 保留空间 (256KB)
└── gmAllEpRecvCount          — 全局 EP 接收计数

阶段 B: 非深度融合路径 (Shallow Dispatch)

当 EXEC_FLAG & EXEC_FLAG_DEEP_FUSE == 0 时,执行独立的 Dispatch 阶段:

if constexpr ((EXEC_FLAG & EXEC_FLAG_DEEP_FUSE) == 0) {
    if constexpr (g_coreType == AscendC::AIV) {
        // AIV 上执行 Dispatch:量化 + AlltoAll 发送
        CamMoeDistributeDispatch<...> dispatcher;
        dispatcher.Init(gmX_, gmexpertIds_, ...);
        dispatcher.Process();
        icache_preload(8);  // 预取 GMM 指令到 icache
    }
    // AIV 完成 → CrossCoreFlag 通知 AIC
    PipeBarrier<PIPE_ALL>();
    Arch::CrossCoreFlag gmm1AivFinished{0};
    if constexpr (g_coreType == AscendC::AIV) {
        Arch::CrossCoreSetFlag<0x2, PIPE_MTE3>(gmm1AivFinished);
    } else {
        Arch::CrossCoreWaitFlag(gmm1AivFinished);
    }
}

阶段 C: GMM1 + SwiGLU + Quant 融合

GmmDeqSwigluQuant<TemplateMC2TypeFunc, Gmm1L1TileShape, Gmm1L0TileShape, ...>(
    gmm1ProblemShape, groupCount_, gmGroupList, gmX1, layoutX1, ...);

这是第一个 GMM kernel,在 AIC+AIV 上执行,内部完成: - GMM1: INT8 × INT8 → INT32 (GroupedMatmul) - PerTokenDequant: INT32 × weightScale × perTokenScale → float - SwiGLU: x * sigmoid(x) * x_right (half-glu) - BlockQuant: float → INT8 + dequantScale (为 GMM2 准备输入)

阶段 D: GMM2 + Combine 融合

// 先初始化 Combiner(AIV 上)
CamMoeDistributeCombine<...> combiner;
combiner.Init(gmGmm2DepOut, gmexpertIds_, gmExpandIdx, ...);

// 再执行 GMM2 kernel(AIC+AIV),Combiner 作为回调注入
GmmDeq<TemplateMC2TypeFunc, Gmm2L1TileShape, ...>(
    gmm2ProblemShape, ..., &combiner);

GMM2 kernel 的 Epilogue 在完成 L0C→GM 写入后,直接调用 combiner.AllToAllSend() 将结果通过 HCCL Window 发送回源 rank。

3.5 GmmDeqSwigluQuant — 类型系统

// GMM1 的 GEMM 类型定义
using AType = Gemm::GemmType<int8_t, layout::RowMajor>;     // 激活 (量化后)
using BType = Gemm::GemmType<int8_t, layout::zN>;           // 权重 (zN 布局)
using CType = Gemm::GemmType<int32_t, layout::RowMajor>;    // 累加器

// Epilogue 类型
using ScaleType = Gemm::GemmType<W1ScaleType, layout::VectorLayout>;      // 权重 scale
using PerTokenScaleType = Gemm::GemmType<float, layout::VectorLayout>;    // per-token scale
using DType = Gemm::GemmType<float, layout::RowMajor>;                    // SwiGLU 输出

Kernel 选择逻辑(fused_deep_moe.h L113-118):

using GemmKernel = typename std::conditional<
    (EXEC_FLAG & EXEC_FLAG_DEEP_FUSE),
    // 深度融合:Dispatch 在 GMM kernel 内部完成(AIV 先做量化+发送,AIC 同时计算)
    Gemm::Kernel::GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspace<...>,
    // 非深度融合:独立的 Dispatch + GMM
    Gemm::Kernel::GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspaceWithShallowDispatch<...>
>::type;

3.6 Tiling 常量

// GMM1 Tile Shape
constexpr uint32_t GMM1_L1M = 256;   // L1 tile M 维
constexpr uint32_t GMM1_L1N = 128;   // L1 tile N 维
constexpr uint32_t GMM1_L1K = 512;   // L1 tile K 维
constexpr uint32_t GMM1_L0K = 128;   // L0 tile K 维 (L1→L0 切分)
constexpr uint32_t GMM1_EPIM = 64;   // Epilogue interleaving M

// GMM2 Tile Shape
constexpr uint32_t GMM2_L1M = 128;
constexpr uint32_t GMM2_L1N = 256;
constexpr uint32_t GMM2_L1K = 512;
constexpr uint32_t GMM2_L0K = 128;
constexpr uint32_t GMM2_EPIM = 32;

// Pipeline 深度
constexpr uint32_t WORKSPACE_STAGES = 4;       // workspace 4 级流水线
constexpr uint32_t CUSTOM_PRELOAD_STAGES = 1;  // preload 1 级
constexpr uint32_t CUSTOM_L1_STAGES = 2;       // L1 双缓冲
constexpr uint32_t CUSTOM_L0A_STAGES = 2;      // L0A 双缓冲
constexpr uint32_t CUSTOM_L0B_STAGES = 2;      // L0B 双缓冲
constexpr uint32_t GMM2_L1A_STAGES = 4;        // GMM2 L1A 4 级 (ResidentA)
constexpr uint32_t GMM2_L0A_STAGES = 4;        // GMM2 L0A 4 级

4. W4A8 变体 (fused_deep_moe_w4a8) — INT4 量化融合

源文件位置: src/cam/comm_operator/ascend_kernels/fused_deep_moe_w4a8/

4.1 设计定位

W4A8 是面向 W4A8 (Weight-INT4, Activation-INT8) 量化 MoE 模型的专用变体。与 Base 的核心差异:

  1. 权重类型从 INT8 降为 INT4 (AscendC::int4b_t),权重存储量减半
  2. 新增 Bias 输入 (gmm1_bias, gmm2_bias, share_gmm1_bias, share_gmm2_bias)
  3. 更大的 L1/L0 tile (L1K=1024, L0K=256) — 补偿 INT4 计算密度的降低
  4. 独立的 host tiling.cpp — 更复杂的参数校验和 workspace 计算
  5. 无 SHMEM 依赖 (requires_shmem: false)

4.2 输入签名差异

W4A8 的 kernel 入口比 Base 多 4 个 Bias 输入:

extern "C" __global__ __aicore__ void fused_deep_moe(
    // ... 同 Base 的 14 个输入 ...
    GM_ADDR gmm1_bias, GM_ADDR gmm2_bias,           // ← 新增
    GM_ADDR share_gmm1_bias, GM_ADDR share_gmm2_bias, // ← 新增
    // ... 输出 + workspace + tiling ...
)

对应的 FusedDeepMoe::Init 也扩展了 Bias 地址绑定:

gmBias1_ = gmm1_bias;
gmBias2_ = gmm2_bias;
gmShareBias1_ = share_gmm1_bias;
gmShareBias2_ = share_gmm2_bias;

4.3 类型系统差异

// W4A8: 权重和激活均为 INT4
using AType = Gemm::GemmType<AscendC::int4b_t, layout::RowMajor>;
using BType = Gemm::GemmType<AscendC::int4b_t, layout::zN>;
using CType = Gemm::GemmType<int32_t, layout::RowMajor>;

// 布局使用 int4b_t
layout::zN layoutWeight1 = layout::zN::template MakeLayout<AscendC::int4b_t>(tokenHiddenSize_, gmm1OutputDim_);

4.4 block_mmad_preload_async_with_callback_w4a8.hpp — 核心优化

这是 W4A8 最独特的文件,实现了 INT4 的 2:1 压缩存储与计算补偿。

4.4.1 INT4 打包比

constexpr int CONSTANT_INT4_PACKING_RATIO = 2;  // 2 个 INT4 打包进 1 个 INT8

// L1/L0 tile 大小计算(注意除以打包比)
static constexpr uint32_t L1A_TILE_SIZE =
    L1TileShape::M * L1TileShape::K * sizeof(ElementA) / CONSTANT_INT4_PACKING_RATIO;
static constexpr uint32_t L1B_TILE_SIZE =
    L1TileShape::N * L1TileShape::K * sizeof(ElementB) / CONSTANT_INT4_PACKING_RATIO;

含义: INT4 权重在内存中以 INT8 存储(2 个 INT4 打包),实际 L1 存储需求减半。这使得 W4A8 可以使用更大的 L1 tile (L1K=1024)。

4.4.2 与 Base 的 block_mmad 关键差异

特性 Base (INT8) W4A8 (INT4)
DispatchPolicy MmadAtlasA2PreloadAsyncWithCallback MmadAtlasA2PreloadAsyncWithCallbackW4a8
L1A/L1B 大小 M*K*sizeof(int8) M*K*sizeof(int4)/2
L0A/L0B 大小 M*K*sizeof(int8) M*K*sizeof(int4)/2
Bias 支持 无 有 (BiasType_ 模板参数)
对齐检查 256b 对齐 256b 对齐(相同)

4.4.3 计算流程

W4A8 的 BlockMmad::operator() 流程与 Base 一致: 1. GM→L1 预取: K 轴分 tile,L1 双缓冲 2. L1→L0 搬运: K 轴进一步切分到 L0 tile 3. TileMmad: 调用硬件 tileMmad 指令完成 INT4×INT4→INT32 乘累加 4. Callback: K 轴最后一轮时触发 callbackBeforeFixpipe / callbackAfterFixpipe(用于触发 Epilogue 的 SwiGLU+Quant)

4.4.4 更大的 Tile Shape

// W4A8 tiling.h
constexpr uint32_t GMM1_L1K = 1024;  // Base 是 512
constexpr uint32_t GMM1_L0K = 256;   // Base 是 128
constexpr uint32_t GMM2_L1K = 1024;
constexpr uint32_t GMM2_L0K = 256;

原因: INT4 权重存储减半 → L1 空间可容纳更大的 K 维 tile → 提高 Cube 引擎利用率。

4.5 Host Tiling 差异

W4A8 有独立的 fused_deep_moe_tiling.cpp(Base 没有),包含:

  1. INT4 权重维度校验: gmm1HLen = shape * INT4_WEIGHT_HIDDEN_SCALE (×8 展开)
  2. Bias 形状校验: CheckGmm2BiasShape()
  3. 更严格的参数范围: MAX_BATCH_SIZE=256, MAX_MOE_EXERT_NUM=512, SUPPORT_TOP_K=12
  4. HCCL 缓冲区检查: CheckHcclBufferSize() 验证窗口大小是否足够
  5. Workspace 计算: 包含 CVSwapBufferSize (Cube workspace) 的精确计算
// W4A8 workspace 计算
size_t CVSwapBufferSize = CeilUp(aicNum * L1_TILE_BYTE_SIZE * CUBE_WORKSPACE_STAGE * sizeof(int32_t), GM_ALIGN_SIZE);
workSpaces[0] = SYSTEM_NEED_WORKSPACE + usrSize;  // SYSTEM_NEED_WORKSPACE = 16MB

4.6 Tiling Key 生成

// W4A8 tiling.cpp
uint64_t tilingKey = 0;
if (xActiveMaskEnable) tilingKey |= EXEC_FLAG_X_ACTIVE_MASK;
if (calShareExpert) tilingKey |= EXEC_FLAG_SHARED_EXPERT;
if (moeExpertNumPerRank != 1) tilingKey |= EXEC_FLAG_DEEP_FUSE;
if (isTensorList) tilingKey |= EXEC_FLAG_TENSOR_LIST;
if (expertSmoothScalesExist) tilingKey |= EXEC_FLAG_SMOOTH_QUANT;
context.SetTilingKey(tilingKey);
context.SetBlockDim(aicNum);

5. FWK 变体 (fused_deep_moe_fwk) — 框架原生范式

源文件位置: src/cam/comm_operator/ascend_kernels/fused_deep_moe_fwk/

5.1 设计定位

FWK 是面向框架原生集成的变体,核心特征:

  1. OPX 框架集成: 通过 lib_ops.h 提供 OPX 兼容的 Op 类
  2. 原生共享专家: sharedExpertNum / sharedExpertRankNum 作为一等公民
  3. 无 SHMEM 依赖: 纯 HCCL Window 通信
  4. 简化模板: 去掉 Scale 类型参数
  5. Permuted Weight: 输入权重名为 gmm1_permuted_weight(预置换布局)
  6. HCCL Context 直连: GetHcclContext<AscendC::HCCL_GROUP_ID_0>()

5.2 输入签名差异

// FWK kernel 入口 — 无 share_gmm1/2_weight,无 x_active_mask
extern "C" __global__ __aicore__ void fused_deep_moe_fwk(
    GM_ADDR x, GM_ADDR expert_ids,
    GM_ADDR gmm1_permuted_weight, GM_ADDR gmm1_permuted_weight_scale,  // ← permuted
    GM_ADDR gmm2_weight, GM_ADDR gmm2_weight_scale,
    GM_ADDR expert_smooth_scales, GM_ADDR expert_scales,               // ← 无 share_smooth
    GM_ADDR output, GM_ADDR expertTokenNums,                           // ← 无 share_output
    GM_ADDR workspace, GM_ADDR tiling)

关键差异: - 无 share_output 输出(共享专家输出直接写回源 rank) - 无 x_active_mask 输入 - 权重名为 permuted_weight(暗示框架侧已做权重置换)

5.3 共享专家的原生支持

FWK 的 FusedDeepMoeFwk::Init 中:

sharedExpertNum_ = tilingData->...sharedExpertNum;
sharedExpertRankNum_ = tilingData->...sharedExpertRankNum;

bool isShareExpert = (epRankId_ < sharedExpertRankNum_);
if (isShareExpert) {
    m_ = maxBs_ * epRankSize_ / sharedExpertRankNum_;  // 共享专家处理全部 token
} else {
    m_ = maxBs_ * epRankSize_ * min(topK_, moeExpertNumPerRank_);  // 路由专家
}
groupCount_ = isShareExpert ? 1 : moeExpertNumPerRank_;  // 共享专家只有 1 组

含义: 共享专家 rank 处理所有 token 的 GMM1/GMM2(groupCount=1),路由专家 rank 处理分配给它的 token。

5.4 lib_ops.h — OPX 框架操作库

lib_ops.h 是 FWK 独有的核心文件,提供 OPX (Operator Extension) 框架兼容的操作类。

5.4.1 文件结构

lib_ops.h
├── 工具函数
│   ├── PipeSync<EVENT>()          — 管道同步
│   └── GetBufferByByte<T>()      — UB 缓冲区分配
├── LibOps namespace
│   ├── MoEContext                — MoE 全局上下文(窗口地址、状态管理)
│   ├── OpDispatchSendToken       — Dispatch 发送端(量化 + 窗口写入)
│   ├── OpDispatchRecvToken       — Dispatch 接收端(窗口读取 + 反量化)
│   ├── OpDequant                 — 反量化操作(INT32 → float)
│   ├── OpSwiglu                  — SwiGLU 激活
│   ├── OpSyncAllCleanAndUpdate   — 全局同步 + 状态清零
│   ├── OpBlockQuant              — 分块量化(float → INT8)
│   ├── OpCombineSend             — Combine 发送端(窗口写入)
│   ├── OpCombineSetFlag          — Combine 标志设置
│   ├── OpCombineRecv             — Combine 接收端(ReducePermute)
│   ├── GmScaleReader             — GM 标量读取器
│   ├── GmPerTokenScaleReader     — GM per-token scale 读取器
│   └── GmSwigluOutputWriter      — SwiGLU 输出写入器

5.4.2 MoEContext — 全局上下文

struct MoEContext {
    __gm__ HcclOpResParam *winContext;   // HCCL 窗口上下文
    GM_ADDR gmStatusDataSpace;           // 状态数据空间
    uint32_t epRankSize, epRankId;
    uint32_t aicNum, aivNum;
    uint32_t moeExpertNumPerRank;
    int32_t dataState;      // 双缓冲状态 (0/1)
    int32_t tokenFlag;      // token 到达标志 (0x55555555 / 0x33333333)
    int32_t vToCFlag;       // AIV→AIC 通信标志
    float sumTarget;        // ReduceSum 目标值(用于 flag 检测)
    uint64_t expertPerSizeOnWin;  // 单个专家在窗口中的空间大小
    uint64_t winDataSizeOffset;   // 窗口数据偏移(双缓冲)
};

窗口地址计算:

GM_ADDR GetWindowStateAddrByRankId(uint32_t rankId) {
    if (epRankId == rankId) return (GM_ADDR)winContext->localWindowsExp;
    return (GM_ADDR)((HcclRankRelationResV2 *)winContext->remoteRes[rankId].nextDevicePtr)->windowsExp
           + dataState * WIN_STATE_OFFSET;  // 双缓冲偏移
}

GM_ADDR GetWindowDataAddrByRankId(uint32_t rankId) {
    // ... 类似,但使用 localWindowsIn + winDataSizeOffset
}

5.4.3 OpDispatchSendToken — 发送端

template <typename XType, uint32_t BUFFER_NUM, bool ENABLE_X_ACTIVE_MASK>
class OpDispatchSendToken {
    // 1. TokenActiveMaskCal: 计算有效 token 数(可选)
    // 2. LoadExpertIds: 加载 expert_ids 到 UB
    // 3. CalAndSendTokenCount: 计算每个专家的 token 数并写入远端状态空间
    // 4. SendToMoeExpert: 量化 token 并写入远端窗口
    //    - DataCopy: GM → UB (读取 token)
    //    - QuantToken: Cast to float → Abs → ReduceMax → scale → Cast to int8
    //    - DataCopy: UB → GM (写入远端窗口)
};

QuantToken 实现(lib_ops.h L524-558):

void QuantToken(...) {
    Cast(xFp32TmpTensor, xInTensor, CAST_NONE, tokenLength);  // bf16/fp16 → float
    Abs(xFp32AbsTensor, xFp32TmpTensor, tokenLength);
    ReduceMax(xRowMaxTensor, xFp32AbsTensor, ..., tokenLength, false);
    float dynamicQuantScale = 127.0 / xRowMaxTensor.GetValue(0);
    // 写入 scale 到 token 尾部的 extra space
    yFp32Tensor.SetValue(tokenLength / sizeof(float), 1.0 / dynamicQuantScale);
    yInt32Tensor.SetValue(tokenLength / sizeof(int32_t) + 1, ctx.tokenFlag);  // 写入 flag
    Muls(xFp32TmpTensor, xFp32TmpTensor, dynamicQuantScale, tokenLength);
    Cast(ytmpInt32Tensor, xFp32TmpTensor, CAST_RINT, tokenLength);  // float → int32
    Cast(yHalfTensor, ytmpInt32Tensor, CAST_ROUND, tokenLength);    // int32 → fp16
    Cast(yInt8Tensor, yHalfTensor, CAST_TRUNC, tokenLength);        // fp16 → int8
}

5.4.4 OpDispatchRecvToken — 接收端

class OpDispatchRecvToken {
    // 1. RecvTokenCountInfo: 轮询状态空间直到所有源 rank 的 flag 到达
    //    - GatherMask: 从 512B 状态块中提取 flag 和 count
    //    - ReduceSum: 检测 flag 总和是否达到目标值
    // 2. RecvToken: 从窗口读取 token 并写入本地 GM
    //    - 轮询 token flag 直到到达
    //    - DataCopy: GM → UB → GM (窗口 → 本地)
    // 3. NotifyNextStage: AtomicAdd 通知 AIC 该组就绪
};

状态检测机制(lib_ops.h L641-695):

// 使用 GatherMask 从 256B 状态块中提取 flag
// 每个 rank 的状态: [flag(0), count(1), pad(2), pad(3)] × 8 blocks = 256B
// src1Pattern=3: 每 4 个 int32 取第 1 个(flag)
// src1Pattern=4: 每 4 个 int32 取第 2 个(count)
do {
    DataCopy(statusFp32Tensor, windowInStatusFp32Tensor, dataCopyParams);
    GatherMask(gatherMaskOutFp32Tensor, statusFp32Tensor, src1Pattern=3, ...);
    ReduceSum(gatherMaskOutFp32Tensor, ..., recStatusNumPerCore);
} while (!(minTarget < sumOfFlag && sumOfFlag < maxTarget));

5.4.5 OpDequant / OpSwiglu / OpBlockQuant — 计算 Op

这三个类是 OPX 框架的标准 Op 接口实现:

// OpDequant: INT32 → float (per-token dequant)
// 输入: cQue(int32), scaleQue(float), perTokenScaleQue(float)
// 输出: outQue(float)
// 计算: float = int32 * weightScale * perTokenScale

// OpSwiglu: SwiGLU 激活
// 输入: inQue(float)
// 输出: outQue(float)
// 计算: swiglu(x) = x[:, :N/2] * sigmoid(x[:, :N/2]) * x[:, N/2:]
//   = x_left * (1 / (1 + exp(-x))) * x_right

// OpBlockQuant: float → INT8 (per-token block quant)
// 输入: inQue(float)
// 输出: dequantScaleQue(float), outQue(int8)
// 计算: abs → Max(左右两半) → scale = Max/127 → quant

5.4.6 OpCombineSend / OpCombineRecv — Combine 端

// OpCombineSend: 将 GMM2 输出写入远端窗口
// 使用 epSendCount 前缀和确定每个 rank 的 token 范围
// DataCopyPad: UB → GM (远端窗口)

// OpCombineRecv: 调用 combiner->ReducePermute()
// ReducePermute 完成 AlltoAll 接收 + 专家输出累加 + 写回输出

5.5 FWK 的 GmmDeqSwigluQuant 差异

FWK 的 GmmDeqSwigluQuant 函数签名与 Base 显著不同:

template <uint32_t EXEC_FLAG, typename XType_, ...>
CATLASS_DEVICE void GmmDeqSwigluQuant(
    GemmCoord problemShape, uint32_t groupCount, GM_ADDR gmGroupList,
    GM_ADDR gmA, layout::RowMajor layoutA,
    GM_ADDR gmB, layout::zN layoutB,
    GM_ADDR gmScale, layout::VectorLayout layoutScale,
    GM_ADDR gmPerTokenScale, layout::VectorLayout layoutPerTokenScale,
    GM_ADDR gmD, layout::RowMajor layoutD,
    GM_ADDR gmDequantScale, layout::VectorLayout layoutDequantScale,
    GM_ADDR gmWorkspace,
    GM_ADDR gmX, GM_ADDR debugGm,                    // ← debugGm 替代 smoothScales
    GM_ADDR gmexpertIds, GM_ADDR gmExpandIdx,
    GM_ADDR gmEpSendCount, GM_ADDR gmResvered,
    GM_ADDR gmExpertTokenNums,
    uint32_t epRankSize, uint32_t epRankId,          // ← 标量参数替代 tiling 引用
    uint32_t moeExpertNum, uint32_t moeExpertNumPerRank,
    uint32_t sharedExpertNum, uint32_t sharedExpertRankNum,  // ← 新增
    uint32_t quantMode, uint32_t globalBs, uint32_t bs,
    uint32_t topK, uint32_t tokenLen)

关键差异: - 无 gmShareX1/gmShareX1Scale/gmShareSwigluOut/gmShareX2/gmShareX2Scale(无独立共享专家 workspace) - 无 gmCombineSend(Combine 由 OPX Op 处理) - 新增 sharedExpertNum/sharedExpertRankNum 标量参数 - 新增 debugGm 参数

5.6 FWK 的 GmmDeq 差异

FWK 的 GmmDeq 使用 layout::nZ(而非 layout::zN)作为权重布局:

using BType = Gemm::GemmType<int8_t, layout::nZ>;  // FWK: nZ
// vs Base:
using BType = Gemm::GemmType<int8_t, layout::zN>;  // Base: zN

zN vs nZ: 这是 CATLASS 中两种不同的矩阵布局。zN 是"Z 形 N 维优先",nZ 是"n 维 Z 形"。FWK 使用 nZ 暗示权重已经过不同的置换处理(与 gmm1_permuted_weight 命名一致)。


6. 三条执行路径的 cam_feature 演进

6.1 路径 1: 非深度融合 (Shallow Dispatch)

AIV: Dispatch (量化 + AlltoAll 发送) ──────────────────────▶
AIC:  等待 ◀── CrossCoreFlag ── 等待结束 ──▶ GMM1+Swiglu+Quant ──▶ GMM2+Combine

触发条件: EXEC_FLAG & EXEC_FLAG_DEEP_FUSE == 0(即 moeExpertNumPerRank == 1)

特点: - Dispatch 在 AIV 上独立执行 - AIV→AIC 通过 CrossCoreFlag 同步 - 适用于单专家 per rank 场景(通信量小)

6.2 路径 2: 深度融合 (Deep Fuse)

AIV: [Dispatch 量化+发送] ─┐
                           ├─▶ 在 GMM Kernel 内部流水线化
AIC: [GMM1 计算] ──────────┘     [SwiGLU+Quant] ──▶ [GMM2+Combine]

触发条件: EXEC_FLAG & EXEC_FLAG_DEEP_FUSE != 0(即 moeExpertNumPerRank > 1)

特点: - Dispatch 嵌入 GMM kernel 的 GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspace - AIV 在 GMM1 计算前完成量化+发送,AIC 同时计算 - 通过 workspace 流水线(WORKSPACE_STAGES=4)实现计算-通信重叠 - 适用于多专家 per rank 场景(通信量大,需要隐藏延迟)

6.3 路径 3: 共享专家 (Shared Expert)

路由专家 Rank:
  Dispatch → GMM1_route → SwiGLU → GMM2_route → Combine

共享专家 Rank (epRankId < sharedExpertRankNum):
  GMM1_share (全部 token) → SwiGLU → GMM2_share → 直接写回

FWK 的实现:

bool isShareExpert = (epRankId_ < sharedExpertRankNum_);
if (isShareExpert) {
    m_ = maxBs_ * epRankSize_ / sharedExpertRankNum_;  // 处理全部 token
} else {
    m_ = maxBs_ * epRankSize_ * min(topK_, moeExpertNumPerRank_);
}
groupCount_ = isShareExpert ? 1 : moeExpertNumPerRank_;

Base 的实现: 通过 EXEC_FLAG_SHARED_EXPERT 标志,在 workspace 中为共享专家分配独立区域(gmShareX1, gmShareX2 等),与路由专家并行计算。

6.4 三条路径的协同

在 cam_feature 上,三条路径可以组合: - 非深度融合 + 无共享专家: tilingKey bit0=0, bit3=0 - 深度融合 + 无共享专家: tilingKey bit0=1, bit3=0 - 深度融合 + 共享专家: tilingKey bit0=1, bit3=1


7. raw_distributed 子模块 — 通信原语解剖

7.1 CamMoeDistributeDispatch — 发送端

文件: fused_deep_moe/op_kernel/fused_deep_moe/raw_distributed/cam_moe_distribute_dispatch.h

7.1.1 核心常量

constexpr uint32_t STATE_OFFSET = 512;        // 每个 rank 的状态空间偏移
constexpr uint32_t STATE_SIZE = 1024 * 1024;  // 1MB 状态空间
constexpr uint64_t WIN_STATE_OFFSET = 512 * 1024;  // 窗口状态双缓冲偏移
constexpr uint64_t STATE_WIN_OFFSET = 900 * 1024;  // 状态在窗口中的偏移
constexpr uint32_t SELF_STATE_OFFSET = 256 * 1024; // 自状态偏移

7.1.2 状态空间布局

窗口状态空间 (每个 rank 1MB):
├── [0, 512KB):     数据状态空间 (dataState=0)
│   ├── rank0: [0, 512B)     — 每个 rank 512B 状态块
│   │   ├── [0, 256B):  flag + count 数组 (64 个 int32)
│   │   └── [256B, 512B): 保留
│   ├── rank1: [512B, 1024B)
│   └── ...
├── [512KB, 1024KB): 数据状态空间 (dataState=1) — 双缓冲
├── [900KB, 932KB):  窗口状态空间 (STATE_WIN_OFFSET)
├── [932KB, 964KB):  组 token 计数 (GROUP_TOKEN_NUM_OFFSET)
└── [964KB, 988KB):  软同步空间 (SOFT_SYNC_OFFSET)

7.1.3 窗口地址计算

GM_ADDR GetWindAddrByRankId(uint8_t ctxIdx, const int32_t rankId) {
    if (curRankId == rankId)
        return (GM_ADDR)(winContext_[ctxIdx]->localWindowsIn) + winDataSizeOffset_ + rankId * OPT_RANK_OFFSET;
    return (GM_ADDR)(((HcclRankRelationResV2 *)(winContext_[ctxIdx]->remoteRes[rankId].nextDevicePtr))->windowsIn)
           + winDataSizeOffset_ + rankId * OPT_RANK_OFFSET;
}

含义: 通过 winContext 获取远端 rank 的窗口地址,winDataSizeOffset_ 实现双缓冲(dataState * WIN_STATE_OFFSET)。

7.1.4 数据空间布局

窗口数据空间 (每个 rank):
├── expert0: [0, expertPerSizeOnWin)
│   ├── token0: [0, hCommuSize)  — token 数据 + extra space (scale + flag)
│   ├── token1: [hCommuSize, 2*hCommuSize)
│   └── ...
├── expert1: [expertPerSizeOnWin, 2*expertPerSizeOnWin)
└── ...

hCommuSize = tokenLength * sizeof(int8_t) + TOKEN_EXTRA_SPACE
TOKEN_EXTRA_SPACE = 512B (存储 scale + flag)

7.2 CamMoeDistributeCombine — 接收端

文件: fused_deep_moe/op_kernel/fused_deep_moe/raw_distributed/cam_moe_distribute_combine.h

7.2.1 CombineCalcInfo 结构

struct CombineCalcInfo {
    uint64_t expertPerSizeOnWin_;    // 单个专家在窗口中的空间
    uint32_t epRankId_;              // 本 rank ID
    uint32_t epWorldSize_;           // EP 世界大小
    uint32_t moeExpertPerRankNum_;   // 每 rank 专家数
    uint32_t axisH_;                 // 隐藏维度
    uint32_t moeSendNum_;            // MoE 发送数
    GM_ADDR epSendCount_;            // EP 发送计数
    __gm__ HcclOpResParam *epWinContext_;  // EP 窗口上下文
    uint64_t winDataSizeOffset_;     // 窗口数据偏移
    uint32_t aivNum_;                // AIV 数量
    uint32_t moeExpertNum_;          // 总专家数
    GM_ADDR metaInfoGm_;             // 元信息 GM 地址
    GM_ADDR allExpertTokenNums_;     // 全局专家 token 数
    GM_ADDR allEpRecvCount_;         // 全局 EP 接收计数
    GM_ADDR combineSend_;            // Combine 发送缓冲
};

7.2.2 SHMEM 集成

Base 变体的 Combine 使用 SHMEM 进行跨 rank 同步:

__aicore__ GM_ADDR GetShmemAddrByRankId(GM_ADDR baseAddr, int64_t rankId) {
    if (epRankId_ == rankId) return baseAddr;
    return (GM_ADDR)aclshmem_ptr(baseAddr, rankId);  // SHMEM 指针转换
}

__aicore__ GM_ADDR GetShmemStateAddrByRankId(int64_t rankId) {
    return GetShmemAddrByRankId(metaInfoGm_ + statusDataSpaceOffset_ + dataState_ * WIN_STATE_OFFSET, rankId);
}

SHMEM 清理(ShmemCleanUp):

void ShmemCleanUp() {
    if (coreIdx_ != 0) return;  // 仅 core 0 执行
    // 清零本地 notify 数据
    Duplicate(cleanTempLt, 0, moeExpertNum_);
    DataCopyPad(localNotifyDataTensor, cleanTempLt, ...);
}

7.2.3 Combine 执行流程

// 1. AllToAllSend: 将 GMM2 输出发送到远端 rank
void AllToAllSend() {
    // 读取 epSendCount 确定每个 rank 的 token 范围
    // DataCopyPad: UB → GM (远端窗口)
}

// 2. ReducePermute: 接收远端 rank 的结果并累加
void ReducePermute() {
    // 从窗口读取 token
    // 按 expert 累加 (CustomAdd)
    // 写回输出 GM
}

// 3. ProcessCombine: 主流程
void ProcessCombine() {
    AllToAllSend();
    ReducePermute();
}

7.3 通信原语总结

操作 方向 机制 触发方
Dispatch Send 本 rank → 远端 rank DataCopy 到远端窗口 AIV
Dispatch Recv 远端 rank → 本 rank 轮询窗口状态 + DataCopy AIV
Count Send 本 rank → 远端 rank DataCopy 到远端状态空间 AIV
Count Recv 远端 rank → 本 rank GatherMask + ReduceSum 检测 AIV
Combine Send 本 rank → 远端 rank DataCopyPad 到远端窗口 AIV (GMM2 Epilogue 回调)
Combine Recv 远端 rank → 本 rank 轮询窗口 + 累加 AIV
SHMEM 同步 跨 rank aclshmem_ptr + DataCacheClean AIC+AIV

8. GEMM/Epilogue 子模块 — 计算内核

8.1 子模块目录结构

fused_deep_moe/op_kernel/fused_deep_moe/
├── gemm/
│   ├── block/
│   │   ├── block_mmad.h                              ← BlockMmad 通用实现
│   │   ├── block_mmad_preload_async_with_callback_resident_a.h  ← GMM2 ResidentA
│   │   └── (W4A8) block_mmad_preload_async_with_callback_w4a8.hpp
│   ├── kernel/
│   │   ├── grouped_matmul_slice_m_per_token_dequant_multistage_workspace.h      ← GMM2 kernel
│   │   └── grouped_matmul_slice_m_per_token_dequant_swiglu_quant_multistage_workspace.h  ← GMM1 kernel
│   └── dispatch_policy.h
├── epilogue/
│   ├── block/
│   │   ├── block_epilogue.h                          ← BlockEpilogue 通用实现
│   │   └── (W4A8) block_epilogue_per_token_dequant.hpp / _swiglu.h
│   ├── tile/
│   │   ├── tile_broadcast_mul.hpp                    ← 行广播乘
│   │   ├── tile_broadcast_one_blk.hpp                ← 单块广播
│   │   ├── tile_swizzle.hpp                          ← Tile 调度
│   │   └── (FWK) tile_stride_muls.h / tile_stride_binary.h
│   └── dispatch_policy.h
└── raw_distributed/
    ├── cam_moe_distribute_dispatch.h
    └── cam_moe_distribute_combine.h

8.2 BlockMmad — 矩阵乘累加块

文件: block_mmad.h (Base), block_mmad_preload_async_with_callback_w4a8.hpp (W4A8)

8.2.1 通用结构

template <class DispatchPolicy, class L1TileShape, class L0TileShape,
          class AType, class BType, class CType, class BiasType,
          class TileCopy, class TileMmad>
struct BlockMmad {
    // 1. InitL1: 初始化 L1 双缓冲
    // 2. InitL0A/InitL0B/InitL0C: 初始化 L0 缓冲
    // 3. operator(): 主计算循环
    //    - K 轴分 tile → GM→L1 预取 → L1→L0 搬运 → TileMmad
    // 4. SynchronizeBlock: 排空流水线
};

8.2.2 流水线机制

K 轴循环:
  for kTileIdx in [0, kTileCount):
    1. GM→L1: copyGmToL1A/L1B (MTE2)
    2. 如果 preloadCount == PRELOAD_STAGES:
       L1TileMmad(preload 最早的 tile)  ← 计算与预取重叠
    3. 存储当前参数到 l1TileMmadParamsList
    4. 更新 preloadCount / l1ListId

L1TileMmad (内部):
  for mPartIdx, kPartIdx, nPartIdx:
    L1→L0A: copyL1ToL0A (MTE1)
    L1→L0B: copyL1ToL0B (MTE1)
    TileMmad: 硬件乘累加 (FIX)
    if isKLoopLast:
      callbackBeforeFixpipe()
      copyL0CToGm (MTE3)
      callbackAfterFixpipe()  ← 触发 Epilogue

8.3 BlockEpilogue — 后处理块

文件: block_epilogue.h

template <class EpilogueDispatchPolicy, class CType, class ScaleType,
          class PerTokenScaleType, class DType, class TileRowBroadcastMul,
          class TileBroadcastOneBlk, class TileOneBlkColumnBroadcastMul,
          class TileCopy, class TileScheduler>
struct BlockEpilogue {
    // 在 L0C→GM 写入前/后执行:
    // 1. PerTokenDequant: INT32 * weightScale * perTokenScale → float
    // 2. SwiGLU: x * sigmoid(x) * x_right (half-glu)
    // 3. BlockQuant: float → INT8 + dequantScale
};

Epilogue 计算流程(以 GMM1 为例):

L0C (int32) → Cast → float
  → RowBroadcastMul(weightScale)        // 乘权重 scale
  → BroadcastOneBlk(perTokenScale)      // 乘 per-token scale
  → SwiGLU:                             // 激活函数
      left = x[:, :N/2]
      right = x[:, N/2:]
      silu = left * sigmoid(left)
      out = silu * right
  → BlockQuant:                         // 量化为 INT8
      abs → rowMax → scale = rowMax/127
      quant = round(x * 127/rowMax)
  → GM (int8) + dequantScale (float)

8.4 GroupedMatmul Kernel

文件: grouped_matmul_slice_m_per_token_dequant_swiglu_quant_multistage_workspace.h

这是 GMM1 的 kernel 级别实现,核心特征:

  1. Grouped Matmul: 多个专家权重组成一个 group,每个 token 选择对应专家的权重做 GMM
  2. Slice M: M 维按 token 切片,每个 AIV 处理一部分 token
  3. PerTokenDequant: 每个 token 有独立的 dequant scale
  4. SwigluQuant: SwiGLU 激活后立即量化
  5. MultiStageWorkspace: 4 级 workspace 流水线

8.4.1 深度融合变体

// 深度融合: Dispatch 在 GMM kernel 内部
template <TemplateMC2TypeClass, class BlockMmad, class BlockEpilogue,
          class BlockScheduler, uint32_t WORKSPACE_STAGES, class ElementGroupList>
struct GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspace {
    // AIV 在 GMM1 计算前完成 Dispatch (量化 + AlltoAll 发送)
    // AIC 同时计算 GMM1
    // 通过 workspace 流水线实现计算-通信重叠
};

// 非深度融合: 独立的 Dispatch + GMM
template <TemplateMC2TypeClass, class BlockMmad, class BlockEpilogue,
          class BlockScheduler, uint32_t WORKSPACE_STAGES, class ElementGroupList>
struct GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspaceWithShallowDispatch {
    // Dispatch 已在外部完成,直接执行 GMM1
};

8.4.2 BlockQuant 内嵌

GMM1 kernel 内部嵌入了 BlockQuant 类,用于 SwiGLU 输出后的量化:

template <class ArchTag>
class BlockQuant {
    // 输入: SwiGLU 输出 (float)
    // 输出: INT8 token + dequantScale
    // 计算:
    //   1. Abs + ReduceMax → rowMax
    //   2. scale = rowMax / 127
    //   3. quant = Cast(Cast(Cast(x * 127/scale, RINT), ROUND), TRUNC)
};

8.5 GMM2 的 ResidentA 策略

GMM2 使用 MmadAtlasA2PreloadAsyncWithCallbackResidentA 策略:

using Gmm2DispatchPolicy =
    Gemm::MmadAtlasA2PreloadAsyncWithCallbackResidentA<
        CUSTOM_PRELOAD_STAGES, GMM2_L1A_STAGES, GMM2_L1B_STAGES,
        GMM2_L0A_STAGES, GMM2_L0B_STAGES, CUSTOM_L0C_STAGES,
        CUSTOM_ENABLE_UNIT_FLAG, CUSTOM_ENABLE_SHUFFLE_K>;

ResidentA 含义: 激活矩阵 A (X2) 在 L1 中常驻(4 级缓冲),因为 GMM2 的输入 X2 来自 SwiGLU 的输出(已在 workspace 中),不需要频繁从 GM 读取。权重 B 仍然需要预取。


9. SHMEM 集成机制

9.1 Base 变体的 SHMEM 使用

Base 变体是唯一 requires_shmem: true 的变体,通过 SHMEM 实现跨 rank 的元数据同步。

9.1.1 SHMEM Workspace 分配

// fused_deep_moe.h Init()
if constexpr (EXEC_FLAG & EXEC_FLAG_ZERO_BUFFER) {
    shmemWorkspaceGM_ = (GM_ADDR)(tilingData->disGmmDeqSwigluQuantGmmDeqComInfo.shmemWorkspacePtr);
}

shmemWorkspacePtr 来自 tiling 数据,指向 SHMEM 分配的窗口空间。

9.1.2 SHMEM Workspace 布局

shmemWorkspaceGM_:
├── gmShareX1 / gmX1          — GMM1 输入 token (int8)
├── gmShareX2 / gmX2          — GMM2 输入 token (int8)
├── gmShareX1Scale / gmX1Scale — GMM1 输入 scale
├── gmShareX2Scale / gmX2Scale — GMM2 输入 scale
├── gmTokenFlag               — token 到达标志
├── gmAllExpertTokenNums      — 全局专家 token 计数
└── gmCombineSend             — Combine 发送缓冲

9.1.3 SHMEM 指针转换

// combine 中的 SHMEM 地址计算
__aicore__ GM_ADDR GetShmemAddrByRankId(GM_ADDR baseAddr, int64_t rankId) {
    if (epRankId_ == rankId) return baseAddr;
    return (GM_ADDR)aclshmem_ptr(baseAddr, rankId);  // SHMEM 指针转换
}

aclshmem_ptr 是 CAM 提供的 SHMEM 指针转换函数,将本地 SHMEM 地址转换为远端 rank 可访问的指针。

9.1.4 双缓冲机制

// dataState 在 {0, 1} 之间交替
winDataSizeOffset_ = dataState * epRankSize * expertPerSizeOnWin * moeExpertNumPerRank;

// 窗口地址 = base + winDataSizeOffset_ + rankId * OPT_RANK_OFFSET
GM_ADDR GetWindowDataAddrByRankId(uint32_t rankId) {
    return baseAddr + winDataSizeOffset_ + rankId * WIN_OPT_RANK_OFFSET;
}

双缓冲作用: 避免上一次迭代的通信数据被当前迭代覆盖。dataState 在每次迭代后翻转。

9.1.5 SHMEM 清理

void ShmemCleanUp() {
    if (coreIdx_ != 0) return;  // 仅 core 0 执行
    // 清零本地 notify 数据
    AscendC::LocalTensor<int32_t> cleanTempLt = cleanUpBuf_.Get<int32_t>();
    AscendC::Duplicate(cleanTempLt, (int32_t)0, moeExpertNum_);
    // DataCopyPad 到远端窗口的 notify 区域
    DataCopyPad(localNotifyDataTensor, cleanTempLt, ...);
}

9.2 W4A8/FWK 的非 SHMEM 通信

W4A8 和 FWK 使用纯 HCCL Window 通信(通过 MC2 框架),不需要 SHMEM:

  • W4A8: 依赖 Mc2InitTiling / Mc2CcTiling 进行 AlltoAll 通信配置
  • FWK: 通过 winContext->localWindowsIn/Exp 直接访问窗口

10. 关键数据结构与内存布局

10.1 FusedDeepMoeInfo (Base/W4A8)

struct FusedDeepMoeInfo {
    uint32_t epRankSize;           // EP rank 数量
    uint32_t epRankId;             // 本 rank ID
    uint32_t moeExpertNum;         // 总 MoE 专家数
    uint32_t moeExpertNumPerRank;  // 每 rank 专家数
    uint32_t quantMode;            // 量化模式
    uint32_t globalBs;             // 全局 batch size
    uint32_t bs;                   // 本 rank batch size
    uint32_t k;                    // topK
    uint32_t h;                    // 隐藏维度
    uint32_t aicNum;               // AIC 数量
    uint32_t aivNum;               // AIV 数量
    uint64_t totalUbSize;          // UB 总大小
    uint64_t totalWinSize;         // 窗口总大小
    uint64_t gmm1HLen;             // GMM1 隐藏维度
    uint64_t shareGmm1HLen;        // 共享专家 GMM1 隐藏维度
    uint64_t shmemWorkspacePtr;    // SHMEM workspace 地址 (Base 独有)
    uint64_t metaInfoPtr;          // 元信息地址 (Base 独有)
    bool isTensorList;             // 权重是否为 TensorList
};

10.2 FusedDeepMoeFwkInfo (FWK)

struct FusedDeepMoeFwkInfo {
    uint32_t epRankSize;
    uint32_t epRankId;
    uint32_t moeExpertNum;
    uint32_t moeExpertNumPerRank;
    uint32_t sharedExpertNum;      // ← FWK 独有:共享专家数
    uint32_t sharedExpertRankNum;  // ← FWK 独有:共享专家 rank 数
    uint32_t quantMode;
    uint32_t globalBs;
    uint32_t bs;
    uint32_t k;
    uint32_t h;
    uint32_t aicNum;
    uint32_t aivNum;
    uint64_t totalUbSize;
    uint64_t totalWinSize;
    uint64_t gmm1HLen;
    bool isTensorList;
    // 注意: 无 shmemWorkspacePtr / metaInfoPtr
};

10.3 TilingData 结构

// Base/W4A8
struct FusedDeepMoeTilingData {
    Mc2InitTiling mc2InitTiling;    // MC2 初始化 tiling
    Mc2CcTiling mc2CcTiling;        // MC2 通信 tiling
    FusedDeepMoeInfo disGmmDeqSwigluQuantGmmDeqComInfo;  // 算子信息
};

// FWK
struct FusedDeepMoeFwkTilingData {
    Mc2InitTiling mc2InitTiling;
    Mc2CcTiling mc2CcTiling;
    FusedDeepMoeFwkInfo disGmmDeqSwigluQuantGmmDeqComInfo;
};

10.4 窗口状态空间布局 (全局)

HCCL Window (每个 rank):
├── DataSpace (数据空间)
│   ├── rank0: [0, expertPerSizeOnWin * moeExpertNumPerRank)
│   │   ├── expert0: [0, expertPerSizeOnWin)
│   │   │   ├── token0: [0, hCommuSize)  — int8 token + 512B extra
│   │   │   └── ...
│   │   └── ...
│   └── ...
├── ExpSpace (状态空间, 1MB)
│   ├── [0, 512KB):     dataState=0 状态
│   │   ├── rank0: [0, 512B)
│   │   │   ├── [0, 256B):  [flag0, count0, pad, pad, flag1, count1, ...]
│   │   │   └── [256B, 512B): 保留
│   │   └── ...
│   ├── [512KB, 1024KB): dataState=1 状态 (双缓冲)
│   ├── [900KB, 932KB):  窗口状态 (STATE_WIN_OFFSET)
│   ├── [932KB, 964KB):  组 token 计数 (GROUP_TOKEN_NUM_OFFSET)
│   └── [964KB, 988KB):  软同步空间 (SOFT_SYNC_OFFSET)

附录 A: 三变体文件清单

Base (fused_deep_moe)

文件 作用
op_kernel/fused_deep_moe.h 主 kernel 类 + GmmDeqSwigluQuant/GmmDeq 函数
op_kernel/fused_deep_moe.cpp kernel 入口 + 64 tiling key 展开
op_kernel/fused_deep_moe_base.h 模板宏 + 通信组结构
op_kernel/fused_deep_moe_tiling.h TilingData + 编译期常量
op_kernel/fused_deep_moe_tiling.cpp (不存在,依赖 MC2 默认 tiling)
op_host/fused_deep_moe_infer.cpp InferShape/InferDataType
op_api/aclnn_fused_deep_moe.{h,cpp} aclnn 接口

W4A8 (fused_deep_moe_w4a8)

文件 作用
op_kernel/fused_deep_moe.h 主 kernel 类 (INT4 类型)
op_kernel/fused_deep_moe.cpp kernel 入口 + Bias 输入
op_kernel/fused_deep_moe_base.h 模板宏 (含 CONSTANT_TWO)
op_kernel/fused_deep_moe_tiling.h TilingData (L1K=1024)
op_host/fused_deep_moe_tiling.cpp 完整 tiling 逻辑 + Bias 校验
op_host/fused_deep_moe_infer.cpp InferShape/InferDataType
op_kernel/fused_deep_moe/gemm/block/block_mmad_preload_async_with_callback_w4a8.hpp INT4 BlockMmad

FWK (fused_deep_moe_fwk)

文件 作用
op_kernel/fused_deep_moe_fwk.h 主 kernel 类 (简化模板)
op_kernel/fused_deep_moe_fwk.cpp kernel 入口 (4 tiling key)
op_kernel/fused_deep_moe_fwk_base.h 模板宏 (OPT_RANK_OFFSET)
op_kernel/fused_deep_moe_fwk_tiling.h TilingData (FWKInfo)
op_host/fused_deep_moe_fwk.cpp tiling 函数
op_host/fused_deep_moe_fwk_infer.cpp InferShape (共享专家)
op_kernel/fused_deep_moe_fwk/lib_ops.h OPX 框架操作库

附录 B: 关键常量对比表

常量 Base W4A8 FWK
GMM1_L1M 256 256 256
GMM1_L1N 128 128 128
GMM1_L1K 512 1024 512
GMM1_L0K 128 256 128
GMM1_EPIM 64 64 64
GMM2_L1M 128 128 128
GMM2_L1N 256 256 256
GMM2_L1K 512 1024 512
GMM2_L0K 128 256 128
GMM2_EPIM 32 32 32
WORKSPACE_STAGES 4 4 4
CUSTOM_PRELOAD_STAGES 1 1 1
CUSTOM_L1_STAGES 2 2 2
GMM2_L1A_STAGES 4 4 4
GMM2_L0A_STAGES 4 4 4
GM_ALIGN_BYTE 512 512 512
STATE_OFFSET 512 — —
WIN_STATE_OFFSET 512KB — —
TOKEN_EXTRA_SPACE 512B — 512B

附录 C: 核心函数调用链

Base 变体 (深度融合路径)

fused_deep_moe()
  └── FusedDeepMoe::Process()
       ├── [if !DEEP_FUSE] CamMoeDistributeDispatch::Init/Process()  [AIV]
       │    ├── SendToMoeExpert()        — 量化 + AlltoAll 发送
       │    ├── AlltoAllDispatch()        — 窗口数据搬运
       │    └── ResetStatus()            — 状态清零
       ├── PipeBarrier<PIPE_ALL>()
       ├── CrossCoreFlag: AIV→AIC 同步
       ├── GmmDeqSwigluQuant()           — GMM1 + SwiGLU + Quant
       │    └── GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspace
       │         ├── BlockMmad::operator()     — GM→L1→L0→TileMmad
       │         ├── BlockEpilogue::Process()  — Dequant + SwiGLU
       │         └── BlockQuant::operator()    — float→INT8
       ├── PipeBarrier<PIPE_ALL>()
       ├── CrossCoreFlag: AIV→AIC 同步
       ├── CamMoeDistributeCombine::Init()  [AIV]
       └── GmmDeq()                      — GMM2 + Combine
            └── GroupedMatmulSliceMPerTokenDequantMultiStageWorkspace
                 ├── BlockMmad::operator()     — ResidentA 策略
                 └── callbackAfterFixpipe → combiner.AllToAllSend()

FWK 变体

fused_deep_moe_fwk()
  └── FusedDeepMoeFwk::Process()
       ├── [if !DEEP_FUSE] CamMoeDistributeDispatch::Init/Process()  [AIV]
       ├── PipeBarrier<PIPE_ALL>()
       ├── CrossCoreFlag: AIV→AIC 同步
       ├── GmmDeqSwigluQuant<EXEC_FLAG, ExpandXType, ...>()
       │    └── GroupedMatmulSliceMPerTokenDequantSwigluQuantMultiStageWorkspace
       │         └── (内部使用 LibOps 的 Op 类)
       ├── PipeBarrier<PIPE_ALL>()
       ├── CrossCoreFlag: AIV→AIC 同步
       ├── CamMoeDistributeCombine::Init()  [AIV]
       └── GmmDeq()                      — GMM2 + Combine
            └── callbackAfterFixpipe → combiner.AllToAllSend()
                 └── OpCombineSend/OpCombineRecv (LibOps)

总结: FusedDeepMoE 三变体共享五阶段融合架构,但在通信机制(SHMEM vs HCCL Window)、量化精度(INT8 vs INT4)、框架集成(原生 vs OPX)三个维度上分化。Base 是通用旗舰,W4A8 服务量化部署,FWK 面向框架原生集成。三者的演进体现了 CAM 从专用算子到通用框架的架构升级路径。

← ZB Combine 算子族 📑 索引 新通信算子 — A2E/E2A/Detour →