Skip to content

feat: add EP memory dispatch and combine - #86

Draft
SilentEmotion wants to merge 1 commit into
mainfrom
codex/ep-memory-dispatch-combine
Draft

feat: add EP memory dispatch and combine#86
SilentEmotion wants to merge 1 commit into
mainfrom
codex/ep-memory-dispatch-combine

Conversation

@SilentEmotion

Copy link
Copy Markdown
Contributor

Summary

  • add memory-mode EP dispatch and combine public APIs, host validation, layout calculation, and launch integration
  • add dispatch/combine AICore kernels with DataAsFlag transport and MXFP8 quantization support
  • extend EP demos, documentation, and unit coverage for masks, shared experts, quantization, and memory layouts

Tests

  • test_tilexr_ep_api_sources (direct C++14 build/run): passed
  • test_tilexr_ep_kernel_sources (direct C++14 build/run): passed
  • test_tilexr_ep_layout (direct C++14 build/run): passed
  • test_tilexr_ep_host_validation with the project ACL stub contract (direct C++14 build/run): passed
  • git diff origin/main...HEAD --check: passed

Validation gaps

  • Full CANN 9.1/bisheng EP build was not run because the current Windows host has no CANN toolchain.
  • Ascend NPU hardware data-plane validation was not run. The PR remains draft until those checks are completed.

@Kur0x

Kur0x commented Jul 29, 2026

Copy link
Copy Markdown
Member

@codex

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0aa50c0656

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// printf("aivId_ %d, time %d, %d, %d\n", aivId_,
// (usedTime_[1] - usedTime_[0])/ 1000 , (usedTime_[2] - usedTime_[1])/ 1000, (usedTime_[3] - usedTime_[2])/ 1000);
// printf("aivId_ %d, time %d\n", aivId_, (usedTime_[3] - usedTime_[0])/ 1000);
return;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Remove the unconditional dispatch-kernel return

Every valid memory-dispatch launch reaches this unconditional return on each AIV, so AllToAllDispatch, CalCumSum, and LocalWindowCopy are all unreachable. Consequently, TileXRMoeEpDispatchMemory* reports a successful launch without producing any dispatch outputs, and a subsequent memory combine can wait indefinitely for data that was never sent.

Useful? React with 👍 / 👎.

Comment on lines +559 to +561
Copy(outTensorInt32, xInTensorInt32, uint64_t(64), uint8_t(blockCntPerToken_), {1, 1, 16, 15});

Copy(outTensorInt32[64], xInTensorInt32[64], uint64_t(56), uint8_t(blockCntPerToken_), {1, 1, 16, 15});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Allocate the full compact payload before dispatch packing

Once the early return is removed, these two Copy operations consume 480 source bytes for every blockCntPerToken_ repeat, but the non-quantized source tensor is allocated with only hAlignSize_ bytes while the metadata starts at that exact boundary, and the MXFP8 source has only quantTensorBytes_ rather than the rounded compact-payload size. Ordinary FP16/BF16 dispatch therefore reads and writes outside its queue tensor for every route, while MXFP8 does so whenever the final 480-byte block is partial, potentially corrupting adjacent UB buffers and the emitted assist metadata.

Useful? React with 👍 / 👎.

const uint32_t compareCount = static_cast<uint32_t>(AlignUp(flagFloatCount, 64U));
pipe_->InitBuffer(packedCheckFlagBuf_, compareCount * sizeof(float));
pipe_->InitBuffer(packedCheckCompareBuf_, AlignUp(compareCount * sizeof(uint8_t), 256U));
pipe_->InitBuffer(packedInputQueue_, 1, compactPayloadBytes_);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Size the receive queue for quantized sharedExpertX rows

When quantMode is 3 or 4 and sharedExpertX is non-null, this queue is sized for the compact FP8 communication payload, but AddSharedExpertX copies a full FP16/BF16 row (rowBytes_) into it. For a typical h=1024, for example, the queue is 1,440 bytes while the copy is 2,048 bytes, so this supported API combination overwrites neighboring UB buffers before accumulation.

Useful? React with 👍 / 👎.

Comment on lines +355 to +356
Copy(packedFloat, sourceFloat, 64U, static_cast<uint8_t>(blockCntPerToken_), {1, 1, 16, 15});
Copy(packedFloat[64], sourceFloat[64], 56U, static_cast<uint8_t>(blockCntPerToken_), {1, 1, 16, 15});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pad the non-quantized combine source before packing

For non-quantized combine rows whose byte length is not divisible by 480, these copies read blockCntPerToken_ * 480 bytes from inputLocal, although that queue is allocated with only align32(rowBytes_) bytes. For example, h=256 creates a 512-byte input tensor but the two-block pack reads 960 bytes, causing an out-of-bounds UB read on every sent row; the source buffer must be sized and padded to the compact payload length.

Useful? React with 👍 / 👎.

DataCopyPadExtParams<int32_t> expertIdsCntCopyPadParams{true, 0U, uint8_t(rightPadding), -1};
DataCopyExtParams expertIdsCntParams{1U, static_cast<uint32_t>(expertIdsMask * sizeof(uint32_t)), 0U, 0U, 0U};
SyncFunc<AscendC::HardEvent::V_MTE2>();
DataCopyPad(validExpertIdsTensor_, expertIdsGMTensor_, expertIdsCntParams, expertIdsCntCopyPadParams);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gather token-mask rows instead of taking a prefix

For a token mask with an inactive token anywhere except the suffix, TokenActiveMaskCal reduces the mask to only its number of true entries and this copy then takes that many expert-ID rows from the start of the tensor. For example, [true, false, true] dispatches tokens 0 and 1 rather than tokens 0 and 2; the active token's output is lost, and memory combine can wait indefinitely for its route while data was instead written for the masked token.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants