# PR357 Green-Context Split MegaMoE 代码review报告

## 1. 范围

- Remote: `git@github.com:RayWang96/DeepGEMM.git`
- 分支: `split_mega_moe`
- 本地 worktree: `pr-357`
- HEAD: `bb837421b`
- 审查方式: 代码review，不跑实验

`pr-357` 分支包含两段独立改动：

| 范围 | Commit | 主题 | 规模 |
|---|---|---|---|
| 核心 PR357 | `bb837421b` | Add green-context split-kernel MegaMoE | 13 files, +3803/-4 |
| 旁路改动 | `41d89ee6c` | Add FP16-weights variant of FP8 MQA logits kernel | 7 files, +668/-9 |

核心工作是 **SM100 FP8/FP4 MegaMoE split pipeline**，不是 SM90/Hopper 实现。它把原本 fused MegaMoE 拆成 `dispatch_l1_swiglu`、`l2_combine`、`combine_reduce` 三个 kernel，并用 CUDA Runtime 13.1 green context 将 K1/K2 放到互斥 SM 分区中并发执行。

---

## 实现概述

### K1: `dispatch_l1_swiglu` (dispatch + L1 GEMM + SwiGLU)

`deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/dispatch_l1_swiglu.cuh` (1013 lines)

K1 将 fused kernel 的 dispatch + L1 + SwiGLU 各阶段整合到一个 kernel 中。

**warp 分工:**

| Warp Index | 数量 | Threads | Role | 所属 Warpgroup |
|---:|---:|---:|---|---|
| 0..`kNumDispatchWarps-1` | 4 (128 threads) | 128 | Route-based dispatch: 扫描 topk_idx，写 route count/entry，NVLink pull token+SF | WG0 |
| `kNumDispatchWarps` | 1 | 32 | TMA A (l1_acts) + SFA loader | WG1 |
| `kNumDispatchWarps+1` | 1 | 32 | TMA B (l1_weights) + SFB loader | WG1 |
| `kNumDispatchWarps+2` | 1 | 32 | MMA issue warp (leader CTA only) | WG1 |
| `kNumDispatchWarps+3` | 1 | 32 | Idle (warpgroup 占位) | WG1 |
| 剩余 | ≥4 (≥128 threads) | 128–256 | Math UMMA + SwiGLU epilogue + FP8 quant + TMA store + L2 arrival mask write | WG2+ |

**寄存器分配 (与 SM100 fused kernel 一致, dispatch=128, TMA=128, epilogue=256):**

| Role | Reg/thread | Threads | 总 Reg |
|---|---|---|---|
| Dispatch | 48 | 128 (4 warps) | 6,144 |
| TMA/non-epilogue | 40 | 128 (4 warps) | 5,120 |
| Math/epilogue | 208 | 256 (8 warps) | 53,248 |
| **总计** | | **512 (16 warps)** | **64,512/64K** |

**关键约束:**
- `kNumDispatchThreads % 128 == 0` → dispatch 独占整数个 warpgroup
- `kNumNonEpilogueThreads == 128` → TMA 恰好一个 warpgroup
- Route-based dispatch: K1 不物化完整 routed token pool，而是在 dispatch warp 中通过 route metadata 边拉取边写 L1 arrival count
- K1 epilogue 写 `l2_arrival_mask`（release-or），通知 K2 可以开始消费

### K2: `l2_combine` (L2 GEMM + Cross-Rank Combine Scatter)

`deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/l2_combine.cuh` (660 lines)

K2 等待 K1 的 L1 output 就绪，执行 L2 GEMM 并将结果 scatter 到目标 rank 的 combine buffer。K2 无 dispatch warp，线程布局从 K1 config 继承 non_epilogue + epilogue。

**warp 分工 (non_epilogue=128, epilogue=256):**

| Warp Index | 数量 | Threads | Role | 所属 Warpgroup |
|---:|---:|---:|---|---|
| 0 | 1 warp | 32 | TMA A (l2_acts) + SFA loader | WG0 |
| 1 | 1 warp | 32 | TMA B (l2_weights) + SFB loader | WG0 |
| 2 | 1 warp | 32 | MMA issue warp | WG0 |
| 3 | 1 warp | 32 | Idle (warpgroup 占位) | WG0 |
| 4–11 | 8 warps | 256 | Math UMMA + BF16 NVLink scatter epilogue | WG1, WG2 |

**精确 warp 统计: 12 warps = 384 threads = 3 warpgroups**

**寄存器分配:**

| Role | Reg/thread | Threads | 总 Reg |
|---|---|---|---|
| TMA/non-epilogue | 40 | 128 (4 warps) | 5,120 |
| Math/epilogue | 208 | 256 (8 warps) | 53,248 |
| **总计** | | **384 (12 warps)** | **58,368/64K** |

**关键设计:**
- 使用独立的 `Kernel2L2Scheduler`，等待 `expert_recv_count_sum` 高位达到 `kKernel1SMs * kNumRanks` 才开始调度
- 每个 pool block 等待 `l2_arrival_mask == expected_mask`（由 K1 epilogue 写入）
- K2 结束前执行 NVLink barrier，保证 K3 reduce 时 combine buffer 跨 rank 可见

### K3: `combine_reduce` (最终 Top-K Reduce)

`deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/combine_reduce.cuh` (142 lines)

**warp 分工 (kNumThreads=512, JIT 模板实例化时设置，覆盖默认值 256):**

| Warp Index | 数量 | Threads | Role |
|---:|---:|---:|---|
| 0–15 | 16 warps | 512 | Top-K reduce: 读取 top-k combine partials (BF16)，FP32 accumulate，BF16 store |

**精确 warp 统计: 16 warps = 512 threads**

**寄存器分配 (轻量 kernel, register 压力低):**

| Role | Reg/thread | Threads | 总 Reg |
|---|---|---|---|
| Reduce | ~32 | 512 (16 warps) | ~16,384 |

K3 不使用 green context，运行在 primary context。它依赖 graph node dependency（等 K1/K2 graph node 结束）和 K2 的 NVLink barrier 保证数据可见。

### Green Context 资源划分

| Context | Kernel | SM 分配 (默认) | Cluster Dim |
|---|---|---|---|
| Green Context 0 | K1 `dispatch_l1_swiglu` | `kernel1_sms` = 96 | 2 |
| Green Context 1 | K2 `l2_combine` | `kernel2_sms` = 52 | 2 |
| Primary Context | K3 `combine_reduce` | 无限制 | 1 |

---

## 2. 代码差异总览

### 2.1 核心 split MegaMoE 文件

| 文件 | 作用 |
|---|---|
| `deep_gemm/mega/__init__.py` | Python API，新增 split buffer 和 `SM100FP8FP4MegaMoESplitGraph` 包装类 |
| `csrc/apis/mega.hpp` | C++ binding，新增 split buffer size API 和 pybind graph class |
| `csrc/jit_kernels/impls/sm100_fp8_fp4_mega_moe_split.hpp` | JIT runtime、配置推导、green context 创建、CUDA graph 构建 |
| `deep_gemm/include/deep_gemm/layout/mega_moe_split.cuh` | 新增 `SplitWorkspace`，扩展 route-based dispatch metadata |
| `deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/dispatch_l1_swiglu.cuh` | K1，路由 dispatch、L1 GEMM、SwiGLU、FP8 quant、L2 arrival mask |
| `deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/l2_combine.cuh` | K2，等待 K1 output、L2 GEMM、跨 rank combine scatter |
| `deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/combine_reduce.cuh` | K3，按 top-k 对 combine partial 做最终 reduce |
| `deep_gemm/include/deep_gemm/impls/sm100_fp8_fp4_mega_moe_split/common.cuh` | split pipeline 的 `state` tensor offset 定义 |
| `csrc/jit/handle.hpp` | lazy-load CUDA 13.1 green context 和 graph node API |
| `deep_gemm/include/deep_gemm/common/utils.cuh` | 新增 rank/token peel helper，用于 route-based pool slot 映射 |
| `deep_gemm/include/deep_gemm/ptx/ld_st.cuh` | 新增 CUDA 13 `longlong4_32a` 兼容和部分 load/store helper |
| `tests/test_mega_moe_split.py` | correctness 和 perf 测试，对 fused kernel 做 bitwise 对比 |

### 2.2 旁路 MQA 改动

| 文件 | 作用 |
|---|---|
| `csrc/apis/attention.hpp` | `weights.dtype == fp16` 时选择新 SM100 FP8 MQA logits kernel |
| `csrc/jit_kernels/impls/smxx_fp8_fp4_mqa_logits.hpp` | 新增 `SM100FP8MQALogitsF16WeightsRuntime` |
| `deep_gemm/include/deep_gemm/impls/sm100_fp8_mqa_logits_f16_weights.cuh` | FP8 input + FP16 weights 的 SM100 2-CTA logits kernel |
| `tests/test_attention.py` | 增加 FP16 weights 路径覆盖 |

---

## 3. Public API 变化

### 3.1 Split symmetric buffer

`deep_gemm/mega/__init__.py` 中 `SymmBuffer` 增加 `split: bool = False`。当 `split=True` 时，buffer sizing 使用 `_C.get_symm_buffer_size_for_mega_moe_split`。

新增 API：

```python
deep_gemm.get_symm_buffer_for_mega_moe_split(...)
```

与 fused buffer 暴露相同的 tensor view：

```python
x, x_sf, topk_idx, topk_weights, l1_acts, l1_acts_sf, l2_acts, l2_acts_sf
```

区别在于 split buffer 的 workspace 头部更大，因为需要 route-based dispatch metadata。输入、pool、combine 区域的语义与 fused 对齐，方便 correctness 对比。

### 3.2 Weight transform

`transform_weights_for_mega_moe` 负责把权重变成 SM100 MegaMoE 需要的 layout：

| 权重 | 变换 |
|---|---|
| L1 weight | gate/up interleave |
| L1 scale factor | gate/up interleave，再做 UTCCP 需要的 transpose |
| L2 weight | 不 interleave |
| L2 scale factor | 做 UTCCP transpose |

### 3.3 Split graph object

新增 Python 包装类：

```python
deep_gemm.SM100FP8FP4MegaMoESplitGraph(...)
graph.replay()
graph.get_green_context_ids()
```

构造函数接受 `states`、`ys`、`sym_buffers`、L1/L2 weights、stats，以及 `kernel1_sms`、`kernel2_sms`、`reduce_sms` 等参数。实际 C++ 构造函数会 JIT 编译三个 kernel，创建两个 green context，并构建一个 CUDA graph。

---

## 4. SplitWorkspace 布局

`layout::SplitWorkspace` 继承原 fused `Workspace`，保留 barrier、expert send/recv count、expert recv count sum、L1 arrival count、L2 arrival mask 等公共区域，同时新增 route-based dispatch 区域。

新增区域包括：

| 区域 | 用途 |
|---|---|
| `src_token_topk_idx[expert][rank][token]` | 记录每个 local expert 收到的来自哪个 rank/token/topk slot |
| `src_route_count[rank][token]` | 记录一个 token 在目标 rank 上命中了几条 top-k route |
| `src_route_entry[rank][token][topk]` | 多 route 时记录 packed route entry |
| `token_src_metadata[pool_token]` | K2 scatter 时恢复目标 rank、原 token、topk slot |

这个设计把 dispatch 从“先复制完整 routed token pool”改成“写路由元数据，按 expert pool 顺序拉取 token”，使 K1 可以边 dispatch、边 L1、边产生 L2 input。

---

## 5. CUDA Graph 与 Green Context

### 5.1 CUDA 13.1 依赖

`sm100_fp8_fp4_mega_moe_split.hpp` 只在 `CUDART_VERSION >= 13010` 下启用真实实现。低于 CUDA Runtime 13.1 时，`SM100FP8FP4MegaMoESplitGraph` 是 stub，构造和 replay 都直接报错。

`csrc/jit/handle.hpp` lazy-load 了以下 runtime symbol：

| API | 用途 |
|---|---|
| `cudaDeviceGetExecutionCtx` | 获取 primary execution context |
| `cudaDeviceGetDevResource` | 查询 SM/workqueue resource |
| `cudaDevSmResourceSplit` | 把 SM 资源切成两个 group |
| `cudaGreenCtxCreate` | 创建 green context |
| `cudaGraphAddNode` | 添加带 context 的 graph node |
| `cudaGraphKernelNodeSetAttribute` | 设置 cluster dim |
| `cudaGraphLaunch` | replay graph |

### 5.2 SM 资源划分

`create_green_contexts()` 读取 device SM resource，按 `kernel1_sms` 和 `kernel2_sms` 切成两个 SM group：

| Context | Kernel | 资源 |
|---|---|---|
| `green_contexts_[0]` | K1 `dispatch_l1_swiglu` | `kernel1_sms` |
| `green_contexts_[1]` | K2 `l2_combine` | `kernel2_sms` |
| `primary_context_` | K3 `combine_reduce` | 未 green-context 限制 |

K1/K2 都用 `cluster_dim=2`，并设置 `coscheduledSmCount=2`。workqueue resource 使用 `cudaDevWorkqueueConfigScopeGreenCtxBalanced`。

### 5.3 Graph node dependency

`build_graph()` 的 dependency 关系：

| Node chain | Dependency |
|---|---|
| K1 nodes | 多 buffer 时 K1 串行依赖前一个 K1 |
| K2 nodes | 多 buffer 时 K2 串行依赖前一个 K2 |
| 第一个 K3 node | 依赖最后一个 K1 和最后一个 K2 |
| 后续 K3 nodes | 串行依赖前一个 K3 |

单 buffer 下语义直接：K1 和 K2 同时启动，K2 在 kernel 内 busy-wait K1 的 arrival mask，K3 等 K1/K2 graph node 都结束后 reduce。

多 buffer 下 K1 chain 和 K2 chain 可以重叠，但 K3 等所有 K1/K2 chain 结束后再开始，不是 per-buffer K3 逐个接在各自 K1/K2 后面。

---

## 6. 三段 Kernel 实现

### 6.1 K1: `dispatch_l1_swiglu`

入口：

```cpp
sm100_fp8_fp4_mega_moe_split_dispatch_l1_swiglu_impl(...)
```

K1 同时承担三件事：

| 阶段 | 行为 |
|---|---|
| Dispatch metadata | 扫描 `topk_idx`，写 expert send count、route count、route entry、remote `src_token_topk_idx` |
| L1 GEMM | 按 expert pool 顺序拉取输入 token 和 SF，做 L1 FP8/FP4 UMMA |
| SwiGLU/quant | epilogue 中做 clamp、SwiGLU、乘 top-k weight、量化成 FP8，写 `l2_acts` 和 `l2_acts_sf` |

关键机制：

| 机制 | 说明 |
|---|---|
| route-based pull | dispatch warp 通过 route metadata 拉取 remote input token，不提前物化全部 token pool |
| duplicate route 去重 | 如果一个 token 对同一目标 rank 有多个 top-k route，用 `route_count` 和 packed route entry 复用一次 remote pull |
| expert count 同步 | 本地写 send count，跨 rank 用 `atomic_add_sys` 汇总 recv count |
| NVLink barrier | dispatch metadata 完成后，通过 `comm::nvlink_barrier` 保证各 rank 可见 |
| L1 arrival count | 每个 pool block 的 token 写入后，`l1_arrival_count` release-add，L1 GEMM warp 等待完整 block |
| L2 arrival mask | K1 epilogue 完成一个 L1 output block 后，对 `l2_arrival_mask` 做 release-or，通知 K2 可消费 |

K1 的 shared memory 与 fused kernel 不同。JIT 侧新增 `get_mega_moe_split_kernel1_pipeline()`，把 dispatch send buffer、expert count、CD staging、barrier、TMA stage 全部纳入 SMEM sizing，避免复用 fused heuristic 导致 SMEM 不足。

### 6.2 K2: `l2_combine`

入口：

```cpp
sm100_fp8_fp4_mega_moe_split_l2_combine_impl(...)
```

K2 只做 L2 和 combine scatter：

| 阶段 | 行为 |
|---|---|
| Scheduling | `Kernel2L2Scheduler` 等待 `expert_recv_count_sum` 的高位达到 `kKernel1SMs * kNumRanks` |
| Readiness wait | 每个 pool block 等待 `l2_arrival_mask == expected_mask` |
| L2 GEMM | TMA load `l2_acts/l2_weights` 和 scale factors，执行 SM100 MXF8F6F4 UMMA |
| Combine scatter | epilogue 将 BF16 L2 output 通过 `sym_buffer.map` 写回目标 rank 的 combine buffer |
| Before reduce barrier | K2 epilogue 结束后执行 NVLink barrier，保证 K3 reduce 前 combine buffer 已跨 rank 可见 |

K2 的 scheduler 使用 `block_idx += kKernel2SMs` 方式分配 block，因此 K2 的工作分区与其 green-context SM 数绑定。

### 6.3 K3: `combine_reduce`

入口：

```cpp
sm100_fp8_fp4_mega_moe_split_combine_reduce_impl(...)
```

K3 是最简单的一段：

| 阶段 | 行为 |
|---|---|
| Grid | 一个 CTA 对应一个 original token |
| Load top-k | 读取该 token 的 `topk_idx` |
| Reduce | 对 `combine_token_buffer[topk_slot][token]` 中的 BF16 partial 做 FP32 accumulate |
| Store | cast 回 BF16，写 `y[token]` |

K3 依赖 graph node dependency 和 K2 内部 NVLink barrier 来保证数据可见。它不使用 green context，也没有被 `reduce_sms` 限制。

---

## 7. 同步与状态设计

### 7.1 Workspace 同步

| 同步对象 | Producer | Consumer | 作用 |
|---|---|---|---|
| `expert_send_count` | K1 dispatch | K1/K2 scheduler | 每个 expert 的发送 token 数 |
| `expert_recv_count_sum` | K1 dispatch | K1/K2 scheduler | 每个 local expert 的总接收 token 数和到达计数 |
| `l1_arrival_count` | K1 dispatch pull | K1 L1 GEMM | pool block 输入 token 是否完整 |
| `l2_arrival_mask` | K1 epilogue | K2 L2 GEMM | L1 output 的 N-block 是否完整 |
| `token_src_metadata` | K1 dispatch pull | K2 combine scatter | scatter 回原 rank/token/topk slot |

### 7.2 `state` tensor

`common.cuh` 定义了一个至少 7 个 `int32` 的 state tensor：

| Offset | 名称 | 当前用途 |
|---:|---|---|
| 0 | `K1ReadyTasks` | 已定义，当前实现中未见核心调度使用 |
| 1 | `K1DoneBlocks` | 已定义，当前实现中未见核心调度使用 |
| 2 | `K2ClaimCounter` | 已定义，当前实现中未见核心调度使用 |
| 3 | `K2DoneTasks` | K2 epilogue 完成 task 后 atomicAdd |
| 4 | `K2DoneBlocks` | K2 kernel block 完成后 atomicAdd |
| 5 | `K3DoneElements` | K3 每 token 完成后 atomicAdd |
| 6 | `K2Checksum` | 已定义，当前实现中未见核心调度使用 |

当前实现主要依赖 workspace arrival/count 和 graph dependency，`state` 更像是调试/进度计数和未来扩展预留。

---

## 8. Correctness 与测试策略

`tests/test_mega_moe_split.py` 是主要验证入口，本文未运行。

测试逻辑：

| 步骤 | 内容 |
|---|---|
| 构造输入 | FP8 activation、FP4 L1/L2 weights、相同 top-k routing |
| 分配 buffer | fused buffer 和 split buffer 分开分配 |
| 跑 fused | 调用 `deep_gemm.fp8_fp4_mega_moe` 得到 reference |
| 跑 split | 构造 `SM100FP8FP4MegaMoESplitGraph` 后 `replay()` |
| correctness | `torch.equal(y_split, y_fused)`，要求 bitwise identical |
| perf | 对 fused CUDA graph 和 split graph 做 best-of-N wall-clock，对比 TFLOPS/HBM/NVLink 粗略指标 |

默认参数：

| 参数 | 默认值 |
|---|---:|
| `num_processes` | 8 |
| `num_tokens` | 8192 |
| `hidden` | 7168 |
| `intermediate_hidden` | 3072 |
| `num_experts` | 384 |
| `num_topk` | 6 |
| `kernel1_sms` | 96 |
| `kernel2_sms` | 52 |
| `reduce_sms` | 148 |

测试注释声称 split pipeline 通常略快于 fused，但这是代码注释，非本文实验结论。

---

## 9. 代码review发现与潜在问题

### 9.1 `reduce_sms` 和 `reduce_work_iters` 当前未实际生效

Python docstring 说 K3 在 `reduce_sms` 上运行，但 C++ `build_graph()` 中 K3 node 使用：

```cpp
add_kernel_node(primary_context_, kernel3_graph_kernel_, num_tokens_, 512, 0, 1, ...)
```

具体情况：

| 参数 | 当前情况 |
|---|---|
| `reduce_sms` | 构造时保存并做正数检查，但未用于 K3 grid 或 green context |
| `reduce_work_iters` | 构造时保存，但未传给 K3，也未影响调度 |
| K3 SM 限制 | 不使用 green context，运行在 primary context |

这不一定是 bug，可能是 API 预留或尚未完成的功能。但文档和实现存在不一致，后续使用不要把 `reduce_sms` 当成有效的 SM partition 控制。

### 9.2 K1/K2 依赖 busy-wait arrival，异常路径可能死锁

K1/K2 之间的真实数据流依赖 workspace 中的 count/mask，而非 graph dependency。K2 会等待 `expert_recv_count_sum` 和 `l2_arrival_mask`。如果 K1 提前失败、route metadata 被破坏、或某个 arrival mask 没有写满，K2 可能长时间 spin 无法退出。

### 9.3 Split buffer 比 fused buffer 更大，且调用者必须显式 reset

SplitWorkspace 增加了 route metadata 区域，buffer size 大于 fused。测试里每次 replay 前都会：

```python
split_buffer.buffer.zero_()
state.zero_()
fill(split_buffer)
```

Public graph API 本身不自动 reset state/workspace。调用者如果 replay 多次，需要自行清零并重新填输入，否则 arrival/count/mask 会残留。

### 9.4 Graph construction 固化 shape 和指针

`SM100FP8FP4MegaMoESplitGraph` 在构造时固化：

| 固化对象 | 后果 |
|---|---|
| `num_tokens`、hidden、intermediate、experts、topk | 不适合动态 shape 直接复用 |
| TMA descriptors | weights/buffer pointer 和 layout 固定 |
| green contexts | 生命周期绑定 graph object |
| graph node params | 多 buffer 列表长度固定 |

动态 token 数或不同权重需要重新构造 graph。

### 9.5 SM100 only

所有新增 split kernels 都要求 `__CUDA_ARCH__ >= 1000`，且 graph 实现要求 CUDA Runtime 13.1+。这不是 SM90/H100/H200 路径。

---

## 10. 与已有 MegaMoE split 方向的关系

pr357 的 split 不是简单的"L1 kernel 后接 L2 kernel"。其关键差异是 **green-context concurrency**：

| 维度 | 常规 split L1/L2 | pr357 green-context split |
|---|---|---|
| K1/K2 launch | 两个 kernel 串行或外部并发 | 一个 CUDA graph 内两个 green context node |
| SM partition | 默认由调度器抢占/共享 | K1/K2 分别绑定固定 SM resource group |
| K2 等待方式 | 通常等 L1 kernel 完成 | K2 kernel 先启动，按 block 等 K1 arrival mask |
| 数据流 | L1 全量完成后 L2 消费 | K1 产生 pool block，K2 可逐 block 消费 |
| K3 | split 后单独 reduce | graph dependency 等 K1/K2 后 reduce |

目标是重叠 dispatch/L1 和 L2/combine，并用固定 SM 切分减少 K1/K2 互相抢占。

---

## 11. FP16-weight MQA logits 旁路改动

这部分不是 split MegaMoE 主线，但在 `pr-357` 分支内。

### 11.1 API dispatch

`fp8_fp4_mqa_logits` 中 `weights.scalar_type() == torch::kFloat16` 时选择新 kernel：

```cpp
sm100_fp8_mqa_logits_f16_weights(...)
```

约束：

| 约束 | 原因 |
|---|---|
| `arch_major == 10` | 只支持 SM100 |
| `seq_len % 4 == 0` | 2-CTA kernel 的 query tiling 没有 per-row bound check |
| 不支持 FP4 Q/KV | 代码显式 assert `not (is_fp4 and weights_is_f16)` |
| FP16 accumulation | QK score 和 per-head weighted sum 都用 FP16 accumulation，速度快但更容易溢出 |

### 11.2 Kernel 结构

`sm100_fp8_mqa_logits_f16_weights.cuh` 是一个 2-CTA cluster kernel：

| 组件 | 说明 |
|---|---|
| Q/KV | FP8 E4M3 |
| weights | FP16 |
| KV scale | FP32 |
| SMEM pipeline | Q、weights、KV、KV scale、KV offsets 多 stage |
| TMEM | 使用 SM100 tensor memory accumulator |
| Launch | `num_specialized_threads=128`，`num_math_threads=256`，`cluster_dim=2` |

这是 attention/MQA 路径优化，不影响 split MegaMoE API。

---

## 12. 结论

pr357 的核心价值是引入了一个面向 SM100/CUDA 13.1 的 **green-context split-kernel MegaMoE execution model**。它不是单纯把 fused MegaMoE 拆成三个 kernel，而是让 K1 和 K2 在一个 CUDA graph 中用不同 green context 同时运行，借助 workspace arrival mask 实现 producer/consumer 流水线。

最重要的实现要点：

| 结论 | 说明 |
|---|---|
| K1/K2 真正并发 | green context 将 `kernel1_sms` 和 `kernel2_sms` 切成独立 SM partition |
| 数据流按 pool block 流水化 | K1 写 `l2_arrival_mask`，K2 等 mask 后消费 |
| dispatch 变为 route-based pull | `SplitWorkspace` 保存 route metadata，减少重复 remote token pull |
| correctness 目标是 bitwise fused | 测试直接要求 `torch.equal(y_split, y_fused)` |
| API 仍有预留/不一致 | `reduce_sms` 和 `reduce_work_iters` 当前未控制 K3 |
| 分支含旁路 MQA 优化 | FP16-weight MQA logits 是独立 sidecar，不属于 MegaMoE split 主链路 |
