Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# A5 Dispatch 可达性裁剪设计

## 目标

精简 `reference/moe_distribute_dispatch_v2_full_mesh_3510_simplified.h`,仅保留
A5 `Init()` 和 `Process()` 流程可能使用的代码,同时保证所有受支持路径的行为不变。

## 范围

- 以 `Init()` 和 `Process()` 作为调用图根节点。
- 除下文明确固定的特性输入外,所有模板实例和运行时分支均视为可能生效。
- 删除不可达成员函数的类内声明和类外定义。
- 删除函数裁剪后没有引用的类成员变量。
- 删除函数和成员裁剪后没有引用的文件级常量。
- 保持现有 `#include` 指令不变。
- 保留公开类型别名、构造函数以及 `Init()`、`Process()` 的受支持行为。

## 固定特性输入

简化后的 A5 参考代码采用以下固定输入:

- `zeroComputeExpertNum` 永远为 `0`。
- `isPerformance` 永远为 `false`。
- `hasElasticInfo` 永远为 `false`。

代码不再读取这些 tiling 字段,也不再保存对应类成员。依赖这些输入的条件将折叠到
固定分支,由此变为不可达的特性代码将被删除。

为了保持调用接口兼容,`Init()` 声明和定义中的 `elasticInfo`、`performanceInfo`
形参继续保留,但不再绑定 GlobalTensor,也不会在函数体中使用。

## 函数候选

应用固定特性输入前,当前词法调用图包含 49 个类外成员函数定义。从 `Init()` 和
`Process()` 出发的传递可达闭包包含 42 个定义。以下 7 个函数已经不可达:

- `AllToAllDispatchA3`
- `CalcBSTokenRange`
- `CalExpertSendNum`
- `SendBSExpertLoop`
- `SendToMoeExpertByBS`
- `SetExpertTokenNums`
- `SplitExpertNumToCore`

这些函数的类内声明和类外定义都将删除。

折叠三个固定特性输入后,以下 6 个函数也会变为不可达:

- `InitElasticInfo`
- `CalAndSendCntByExp`
- `RecordRankCommDuration`
- `GenerateGatherMaskTensor`
- `MaskZeroComputeExpert`
- `ZeroComputeExpertMaskCal`

分支折叠完成后会重新计算调用图。只有确认不属于 `Init()`、`Process()` 传递可达
闭包的函数才会继续删除。

## 分支折叠

实现时进行以下等价替换:

- Mask Buffer 的分配条件简化为 `isTokenMaskFlag_ || isExpertMaskFlag_`,删除
zero 专家 Mask 初始化和计算。
- `CalCumSum()` 直接调用 `CalAndSendCntByRank()`。
- Rank 地址计算直接使用非扩缩容场景的 Rank ID,删除所有
`isScalingDownFlag_` 重映射分支。
- LocalWindow 源数据索引条件简化为 `if (!isShareExpertRankFlag_)`。
- 删除性能 Buffer、计时调用和性能输出拷贝。
- `Init()` 保留兼容形参,但不创建弹性信息或性能信息 GlobalTensor。

## 成员变量候选

删除原有不可达函数后,以下 18 个私有成员不再有引用:

- `axisHExpandXAlignSize_`
- `cleanStatusTensor_`
- `cumSumTime1Tensor_`
- `cumSumTime2Tensor_`
- `cumSumTimes_`
- `cumSumUB_`
- `dealRankPerCore_`
- `delLastExpertId_`
- `flagPadOffset_`
- `gatherTmpTensor_`
- `maskSizePerExpert_`
- `remainderExpertNum_`
- `sharedTmpBufTensor_`
- `statusSumOutTensor_`
- `syncOnCoreTensor_`
- `tempTime1Tensor_`
- `tempTime2Tensor_`
- `tokenNumToExpertTensor_`

编辑后会重新进行引用分析。只有声明成为唯一剩余引用时,成员才会被删除。

固定特性输入还会使以下 12 个成员失去用途:

- `zeroComputeExpertNum_`
- `hasElasticInfoFlag_`
- `isScalingDownFlag_`
- `isPerformanceFlag_`
- `elasticInfoGMTensor_`
- `elasticInfoTensor_`
- `elasticInfoBuf_`
- `performanceInfoGMTensor_`
- `performanceInfoTensor_`
- `performanceFlagTensor_`
- `performanceInfoBuf_`
- `performanceFlagBuf_`

如果共享 Mask 或临时 Buffer 仍被 Token Mask、Expert Mask 或正常 Dispatch 路径
使用,则继续保留。

## 文件级常量候选

以下 4 个常量在可达代码中没有引用:

- `AIV_STATE_SIZE`
- `MIN_ACTIVE_BS_FOR_BS_MODE`
- `SFFVALUE_SIZE`
- `SYNC_OFFSET`

删除性能打点后,`DURATION_OFFSET` 也会失去引用。

只有在编辑后的引用扫描确认常量仅剩声明时,才会将其删除。

## 编辑方法

删除函数定义时使用大括号配平后的精确范围,不通过下一个函数签名推断删除边界,
避免误删相邻的模板声明和注释。函数声明、成员变量和常量使用局部补丁删除。

可达函数体只允许进行上文明确列出的固定输入分支折叠。其他可达代码不进行格式化
或重写。

## 验证标准

处理结果必须满足以下检查:

1. `Init()` 和 `Process()` 仍然存在,其可达调用闭包不存在缺失的类成员函数定义。
2. 每个保留的类外函数定义都有对应的类内声明。
3. 原有 7 个不可达函数和新增 6 个特性函数均不存在声明、定义或调用点。
4. `zeroComputeExpertNum_`、`hasElasticInfoFlag_`、`isScalingDownFlag_`、
`isPerformanceFlag_` 不再出现。
5. `elasticInfo`、`performanceInfo` 仅作为 `Init()` 兼容形参存在,不在函数体中使用。
6. 已删除的成员变量和常量不存在残留引用。
7. 可达函数体中使用的成员标识符仍有对应类成员声明。
8. 预处理指令和大括号保持配平。
9. 文件保持无 BOM 的 UTF-8 编码和 LF 换行。

该参考头文件不参与当前 Windows 构建,并依赖外部 Ascend C 头文件,因此本阶段采用
结构化验证,不执行本地编译。
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
# EP Dispatch Memory Reference Port Design

## Goal

Port the complete reachable non-quantized A5 full-mesh dispatch behavior from
`reference/moe_distribute_dispatch_v2_full_mesh_3510_simplified.h` into
`src/ep/kernels/tilexr_ep_dispatch_memory_kernel.cpp`.

The TileXR kernel is launched directly through
`launch_tilexr_ep_dispatch_memory_kernel`. It does not expose the reference
implementation's separate `Init()` and `Process()` calling convention.

## Supported Scope

The first version supports:

- FP16 and BF16 input/output with identical input and output types;
- normal MoE experts;
- shared experts, including multiple ranks per shared expert;
- no active mask, token mask `[bs]`, or expert mask `[bs, topK]`;
- count and prefix-sum forms of `expertTokenNumsOut`;
- the reference AIV split between dispatch and count/cumsum work;
- the reference 512-byte DataAsFlag token slots and state-window protocol;
- the reference local output compaction order.

The first version rejects:

- all quantization modes;
- smooth-scale input and scale outputs;
- differing input and output types;
- TP execution;
- elastic rank remapping, zero-compute experts, and performance recording,
which are already removed from the simplified reference source.

## Kernel Organization

`tilexr_ep_dispatch_memory_kernel.cpp` contains the ported implementation.
The obsolete `tilexr_ep_dispatch_memory_helpers.h` chunk/source-slot protocol
is deleted and is not used as an implementation reference.

The kernel constructs a `TPipe` and invokes one internal `Run()` entry. `Run()`
contains the reference initialization work followed by the reference process
work. The following reference functions retain their algorithms, AIV ownership,
and call relationships:

- `SetTilingDataAndCal`
- `SetDataStatus`
- `TokenToExpert`
- `SplitToCore`
- `SendToSharedExpert`
- `SendToMoeExpert`
- `CalcSendTokenBufNum`
- `AllToAllDispatch`
- `AllToAllDispatchA5`
- `CalTokenSendExpertCnt`
- `CalAndSendCntByRank`
- `BufferInit`
- `WaitDispatchClearStatus`
- `GatherSumRecvCnt`
- `GetCumSum`
- `WaitDispatch`
- `CalRecvAndSetFlag`
- `CalCumSum`
- `WaitCumSumFlag`
- `SetValidExpertInfo`
- `CheckDataArriveWithFlag`
- `CopyInAndOut`
- `WaitAndFormatOutput`
- `RunPosRecord`
- `LocalWindowCopy`
- token-mask and expert-mask calculation helpers

Quantization-only functions and branches are removed rather than stubbed.

## Communication Context Mapping

The reference A5 context places a one-MiB state area before the data window.
TileXR reproduces that relationship inside each peer's IPC data region:

```text
peerWindowBase(rank) = commArgs.peerMems[rank] + IPC_DATA_OFFSET
stateWindow(rank) = peerWindowBase(rank)
dataWindow(rank) = peerWindowBase(rank) + 1 MiB
statusDataSpace = stateWindow(selfRank)
```

The first one MiB therefore keeps the reference layout:

- ping state 0: `[0, 384 KiB)`;
- ping state 1: `[384 KiB, 768 KiB)`;
- per-AIV run state from `768 KiB`;
- cumsum exchange from `868 KiB`;
- cumsum completion flags from `876 KiB`.

The mapping does not use or overwrite TileXR's flag region before
`IPC_DATA_OFFSET`.

The data window starts after the one-MiB state area. Its two halves use the
reference `dataState * (totalWinSize / 2)` selection and retain the combine
reserve prefix and the dispatch DataAsFlag layout.

## Local Workspace

The reference cumsum path requires `workspaceGM`, replicated once per AIV.
TileXR reserves this workspace at the tail of the local IPC data region:

```text
workspaceStatusNum = epWorldSize * moeExpertNumPerRank
workspaceBytes = align32(aivNum * workspaceStatusNum * sizeof(int32_t))
totalWinSize = IPC_BUFF_MAX_SIZE - 1 MiB - workspaceBytes
workspaceGM = local dataWindow base + totalWinSize
```

Only the local rank accesses this workspace. The reservation nevertheless uses
the communicator-wide maximum receive-status count rather than the local
`rscvStatusNum`. This keeps `totalWinSize` and both dispatch-half offsets
identical on shared-expert and MoE-expert ranks, so remote payload addresses
match the receiver's polling addresses. Host validation checks that each data
state half can contain the combine reserve and every reference expert segment
before launch.

## Launch Interface

The internal launch interface becomes:

```cpp
void launch_tilexr_ep_dispatch_memory_kernel(
uint32_t blockDim,
void *stream,
GM_ADDR commArgs,
GM_ADDR x,
GM_ADDR expertIds,
GM_ADDR xActiveMask,
GM_ADDR expandXOut,
GM_ADDR expertTokenNumsOut,
GM_ADDR epRecvCountsOut,
GM_ADDR assistInfoForCombineOut,
int64_t bs,
int64_t h,
int64_t topK,
int64_t moeExpertNum,
int64_t sharedExpertNum,
int64_t sharedExpertRankNum,
int64_t globalBs,
int64_t expertTokenNumsType,
int64_t activeMaskType,
int64_t dtype,
int64_t magic);
```

`CommArgs` supplies rank, world size, and peer addresses. `blockDim` supplies
the reference `aivNum`. Window sizes, UB sizes, core-group sizes, and offsets
are derived by the exact reference formulas and validated on the host.

`magic` is the communicator-wide invocation sequence. Its low bit selects the
reference ping-pong state half consistently across ranks; TileXR IPC buffers do
not provide the pre-synchronized state bit assumed by the HCCL/MC2 context.

The old route-count, chunk-count, offset, source-slot, payload, and total-size
arguments are deleted. `magic` is retained solely for communicator-wide state
selection.

Each receive-count status occupies one 32-byte block. The last two `int32`
fields store the count followed by the `float(1.0)` arrival flag. This adapts
the reference status block to TileXR's existing payload-before-tail-flag
ordering. The sender copies the complete block, or strided complete blocks,
with one `DataCopy`; the receiver polls the tail flags before consuming the
adjacent counts. The
memory dispatch path must not add a separate `SyncCollectives` ready message,
because that would split one reference transaction into a count write followed
by another remote flag write.

## Active Mask Contract

The public API adds an active-mask type because a pointer alone cannot identify
the reference tiling flags:

```text
NONE = xActiveMask must be null
TOKEN = xActiveMask points to [bs]
EXPERT = xActiveMask points to [bs, topK]
```

Token and expert mask modes are mutually exclusive, matching the supported
reference tiling cases.

## Shared Expert Contract

Shared expert ranks are the leading EP ranks, as in the reference code.
Validation requires:

- `sharedExpertNum == 0` iff `sharedExpertRankNum == 0`;
- `sharedExpertRankNum % sharedExpertNum == 0` when shared experts exist;
- `sharedExpertRankNum < rankSize`;
- `moeExpertNum % (rankSize - sharedExpertRankNum) == 0`.

The port retains `rankNumPerSharedExpert`, `idInSharedGroup`, the shared-expert
AIV allocation formula, and the reference destination-rank formula.

## Output Compatibility

`expandXOut`, `expertTokenNumsOut`, and `epRecvCountsOut` keep the reference
ordering and values. Reference `sendCountsOut` maps to TileXR
`epRecvCountsOut`.

TileXR keeps its four-int `assistInfoForCombineOut` record:

```text
[sourceRank, sourceTokenIndex, topKIndex, expertId]
```

The first three fields are the reference `expandIdxOut` triple. The fourth
field is the TileXR extension required by the current combine path. Shared
expert records use the same `topK + sharedExpertIndex` convention as the
reference code.

## Host Validation

The memory-dispatch host path:

- rejects quantization and scale-related inputs;
- rejects TP;
- validates EP rank/world values against `CommArgs` when explicitly supplied;
- derives `globalBs` as `bs * rankSize` when the public API passes zero;
- validates the active-mask pointer/type pair;
- validates all reference UB and IPC-window size formulas;
- obtains the A5 vector-core count and launches that exact block dimension.

## Testing

Tests are added or updated before implementation to cover:

- the reduced launch signature and removal of chunk/source-slot parameters;
- deletion of `tilexr_ep_dispatch_memory_helpers.h`;
- presence of the reference dispatch, count/cumsum, DataAsFlag, compaction,
shared-expert, token-mask, and expert-mask paths in the target kernel;
- active-mask pointer/type validation;
- general shared-expert rank grouping;
- rejection of quantization and TP;
- reference state/data/workspace layout calculations and overflow rejection;
- compatibility of the four-field assist tuple;
- host and source-guard unit suites;
- A5 kernel compilation when the CANN environment is available.
Loading