Repository navigation
Conversation
39ecef2 to
7befb00
Compare
ksiyuan
left a comment
There was a problem hiding this comment.
Reviewed at 7befb006 against 7ace946.
The gain itself is credible and I would keep it: halving the A2E payload is a real
effect, the +34.5% survives a rebase with both sides drifting by the same ~2.5%,
the variance warning is unusually honest, and E2a at 49.5% of Attention-side
device time is consistent with the throughput delta. What follows is about scope,
patch contract, and one accuracy number that does not fit its own explanation.
All of it is from code reading plus the numbers in this PR body — there is no
torch/torch_npu on my host, so I ran no device validation.
[P1] Drop the pass-through path (AFD_NPU_CAMP2P_MXFP8_DIRECT) from this PR
afd_plugin/envs.py:26, afd_plugin/connectors/npu/camp2p.py:442-448,871-872,890,
afd_plugin/model_executor/models/npu/deepseek_v4.py:483-516,
afd_plugin/compat/patches/npu/moe_mxfp8_scale.py:128-372
Pass-through is 6.8% slower and GSM8K is 92.27% vs 93.86% for mode 0 — 1.59
points, about 3x the ±0.5 spread this PR states for the benchmark. The cost is
explained; the accuracy is not, and mechanically it should be near-neutral:
pass-through hands the routed experts the same E4M3 data plus the scale it was
quantized with, and only skips one fused re-quantization. A 3-sigma drop points at
scale semantics, not at quantization cost. Two candidates:
- The GMM's scale algorithm or grouping may differ from
get_dynamic_mx_quant_scale_alg(), which makes feeding the transport's scale as
pertoken_scalea systematic bias. - A stale scale is reused.
moe_mxfp8_scale.py:191early-returns without clearing
AFD_MXFP8_SCALE_ATTR;:231-232stages it onprepare_finalizeand on
moe_config, both cached byget_moe_comm_methodper (comm type, config) for
the process lifetime;:291-293reads it back throughgetattrfallbacks.
Reachable: run an all-gather batch (_moe_requires_model_dtypefalse,x_scale
pinned atcamp2p.py:890), then a dispatch batch (camp2p.py:871returns true
→direct=False→x_scalenever set → the model pinsNone→forward
early-returns), and:318installs the previous batch's gathered scale as
pertoken_scale. By this file's own docstring that makes the routing op take
quant_mode=-1permute-only and skipnpu_dynamic_mx_quant, so a BF16
activation is consumed as if it were already quantized.
Keeping the path "so the trade-off remains reproducible" does not need production
code — the numbers are already in this PR body. Removing it also removes all three
patched upstream functions, the runner.routed_experts /
runner.ascend_shared_experts hard dependency that deepseek_v4.py:483-516 adds
to the default path (5 setattr per layer for values that are always None when
DIRECT=0 plus 2 attribute reads), and the aivec error 263 operator limit the
recipe README documents at ~14,288 gathered rows.
If you keep it: clear the pinned attributes in the not pinned branch of
forward, reject DIRECT=1 in CAMP2PExtraInfo.validate_supported so it cannot
be switched on by accident, and fix or explain the accuracy.
[P1] The vLLM-Ascend patch does not meet the AGENTS.md patch contract
afd_plugin/compat/patches/npu/moe_mxfp8_scale.py:5,154,270,360,208-232,330-349
- No pinned upstream ref. The docstring at
:5names two modules only, while
ascend_platform.py:5pins a commit (8d4409d...). Use the
vLLM-Ascend revision this PR's Test Environment table already records. - All three patched functions are
_original_*delegation instead of an upstream
copy with# ### PATCH START/ENDmarkers:forward:154,_prepare_with_dp_group:270,
_prepare_gate_up_input:360. Onlyforwardcalls out the exception; the other
two do not, and_prepare_gate_up_inputis small enough to expand locally. A
reviewer cannot check the return-tuple contract or thequant_type/
replace_allreduceordering against the tag. - The compatibility probes AGENTS.md tells us to avoid are pervasive:
getattr
at:208,216,224,228,230,291,293,330,334,362,except TypeErroraround
get_moe_comm_methodat:220, anddir()plusprintof candidate names at
:341-346. - These probes demonstrably did not buy stability — this area needed
6b62e38,
2198f91,324c819,3e48e9b,6d996ce,9b76102on the source branch to
chase exactly the signature and attribute churn they hide. And they do not even
protect:deepseek_v4.py:484,496reads the same attributes directly, so an
upstream rename fails there first.
Fix: copy the three upstream bodies from the pinned revision, keep only the marked
AFD deltas, pin the commit in the docstring, drop the probes and the print.
[P2] The shipped configuration still hard-depends on select_moe_comm_method
afd_plugin/connectors/npu/camp2p.py:870-873
not self._moe_requires_model_dtype(batch_size) and camp2p_mxfp8_direct_enabled()
evaluates the left operand first, so with DIRECT=0 — the default, and the recipe
default — the receive path still imports MoECommType and
select_moe_comm_method from vllm_ascend.ascend_forward_context and calls the
selector on the first receive per batch size, then discards the result. A private
vLLM-Ascend symbol becomes a hard dependency of the default path for a decision
that is never used. Swapping the two operands fixes it.
[P2] The profiler table does not support the causal claim it is used for
The 48.6% is computed from max (11,366 → 5,842 µs) while mean moves the other
way by 6x (421 → 2,594 µs). The PR notes that the two traces cover different step
counts (45,279 vs 4,601 calls), which makes max non-comparable for the same
reason it makes the totals non-comparable.
The PR's own fit also disagrees with it: 3.63 ms + 0.72 µs × rows at 3072 rows
is 5.84 ms/call, and mode 0 at 2.52 µs × rows is 7.74 ms/call — that is
−24.5%, not −48.6%. And 43 layers × 7.74 ms is ~251 ms per step against a measured
~53 ms step (230,520 token/s ÷ 4 ranks ÷ 3072), which cannot be. The fit and the
trace window appear to describe different regimes.
Please either provide a matched A/B trace (same step count, same row distribution)
or drop the table and keep only E2a at 49.5% of Attention-side device time, which
is the number that actually supports the throughput delta.
[P2] Evidence provenance and gate state
- The A/B table was produced with "plugin built from this branch plus the #444
operator". #444 is[WIP], open,mergeable: UNKNOWN, DCOACTION_REQUIRED.
This PR cannot exercisequant_mode=4on its own, and the user-guide section
explicitly needs a rebase after #444 lands, so the two halves are individually
unverifiable. Either state #444 as a hard prerequisite and land it first, or
review the two together. gh pr checksreports only DCO, and--requiredreturnsno required checks reported, so the Buildkitetest-readygate has not validated the 25 tests the
PR body says pass locally.- No decode data point. The mechanism predicts the gain disappears at small row
counts — the PR's own fixed-round-trip argument, and the −0.3% at 8 concurrent —
andrecipe/README.mdlists this recipe underPrefillwhile the other CAMP2P
recipe isDecode. Please add a decode measurement or state the scope as
prefill-only.
[P2] Design pages and the patch inventory were not updated
docs/design/module/connector_contracts.md:95still says the runtime "rejects
gate-on-Attention and any nonzero quantization mode".docs/design/module/execution_platforms.mdstill pins
connector_extra_config.quant_mode=0for the Ascend V1 CAMP2P row, with no new
row or evidence entry for mode 4.docs/design/module/compatibility_and_patches.md:129-133lists every NPU patch
module with its targets, validation paths and a removal condition;
npu/moe_mxfp8_scale.pyis absent, so the new patch has no documented removal
plan, which the AGENTS.md patch requirement asks for.
[P2] Duplicated constants, and .gitattributes guards a path that does not exist
4and32each live in more than one place:afd_plugin/envs.py:16-17,
afd_plugin/connectors/npu/camp2p.py:88-96,
afd_plugin/compat/patches/npu/moe_mxfp8_scale.py:43. And
afd_plugin/compat/npu/feature_validation.py:71-72imports the private
_A2E_QUANT_MODE_MXFP8from the connector while the public pair sits inenvs.py.camp2p.py:185:raw.get("quant_mode", camp2p_quant_mode())evaluates the
default eagerly, so a malformedAFD_NPU_CAMP2P_QUANT_MODEraises even when
connector_extra_configsuppliesquant_modeexplicitly..gitattributes:5-9addspatches/**/*.patch -textandpatches/**/*.md text eol=lf, but this tree has nopatches/directory, zero*.patchfiles,
and nothing references such a path. The CRLF-versus-git applyhazard the
commit describes is not addressed by it.tests/unit/compat/npu/test_a2e_mxfp8_contract.py:23redeclares
_A2E_MX_MAX_TOTAL_RANKS = 64instead of importing it, so the boundary
assertion tracks the test rather than the product;:100-110cannot fail on a
CPU host.mx_dequantize_a2e_activation(the E8M0 exponent reconstruction) is
pure torch math with no unit test, where a wrong exponent bias would only ever
show up as accuracy drift.
Happy to help with any of these. The smallest version of this PR that keeps the
measured win is: connector send/receive quantization, the two env switches, the
docs, the recipe, and the non-AFD baseline — with the patch file, the model-side
pinning, and the pass-through path removed.
803ff11 to
0650642
Compare
|
Thanks — reworked against this review. The branch was rebuilt from
Still open: I have not added a matched A/B trace for the profile question. Say the word if you |
cd62ac5 to
e88eaae
Compare
ksiyuan
left a comment
There was a problem hiding this comment.
Re-reviewed at e88eaae. All seven findings from the previous review are resolved —
and resolved by removal rather than by patching, which is what I would have asked
for:
- Pass-through is gone, and with it
npu/moe_mxfp8_scale.py, the model-side
pinning, thehidden_states_fp32payload field andCAMP2PTransferState.x_scale.
envs.pynow carries only the two mode values, so
connector_extra_config.quant_modereally is the single switch. I grepped for
dangling references to the deleted module, the removed env switches, the deleted
recipe scripts andinspect_afd_trace.py— all clean, and
recipe/npu/CAMP2pAFDConnector/deepseek_v4_flash/correctly holds only the
README with no.shreference left. _moe_requires_model_dtypeis gone, so the default path no longer reaches
select_moe_comm_method.- The per-operator table is dropped and the 49.5% share is stated with the same
caveat I raised. Showing the 92.87% run in the accuracy table is the right move —
it makes the spread concrete instead of asserted. connector_contracts.mdandexecution_platforms.mdare updated and accurate,
including "measured for prefill-dominated load only"..gitattributesremoved, single constant source inenvs.py, and the eager
raw.get(...)default fixed.test_rank_limit_matches_the_connectorplus
TestMxfp8Dequantization(127/128/126 → 1.0/2.0/0.5, and the short last group)
close exactly the two gaps I named — the E8M0 exponent bias is now pinned against
a value known by construction, which is the only way to catch it without a
device run.
Three items left, all documentation.
[P2] The A5 sample command in the user guide cannot do what it claims on this tree
docs/npu/CAM_P2P_CONNECTOR_USER_GUIDE.md:228-233
The guide documents
AFD_TEST_DEVICES=2,3 AFD_TEST_QUANT_MODE=4 python tests/unit/compat/npu/a2e_e2a_a5.py
and states that it "checks both activation and scale bytes for both FP8 formats and
compute_gate=0 and 1", and that "default AFD_TEST_QUANT_MODE=0 retains the BF16
roundtrip". At e88eaae, tests/unit/compat/npu/a2e_e2a_a5.py reads only
AFD_TEST_DEVICES, AFD_TEST_E, AFD_TEST_A, AFD_TEST_WORLD and AFD_TEST_PORT;
it has no AFD_TEST_QUANT_MODE, no MXFP8 path, and the scales it passes are the
routing weights, not MX block scales. So the documented command silently runs the
BF16 roundtrip and reports success.
This paragraph is #444's text, and #444 is where the sample is upgraded. Suggest
moving that whole block (the AFD_TEST_* command and the three sentences after it)
out of this PR and leaving it to #444 — otherwise the two PRs also collide in this
file.
[P2] TTFT contradicts itself across two files this PR edits
recipe/README.md:40 says "−19% TTFT"; the model README says
TTFT median 3748 ms → 2905 ms (−22.5%). The previous version's 2995 ms would be
−20.1%, so −19% matches neither the current nor the previous median. If −19% is the
mean rather than the median, please name the metric — right now the same result is
two different numbers in two files this PR touches.
Nit: the quant_mode table row in the same guide says mode 4 transports
"E4M3/E5M2" activations, but the connector hardcodes E4M3
(_A2E_MX_ACTIVATION_DTYPE); E5M2 is operator-level only. One clause saying the
connector emits E4M3 would settle it.
On your question: I would not go back and capture a matched A/B trace for the
operator table. The table is gone, the 49.5% share is the number that carries the
argument, and a per-operator delta does not change any review conclusion here — it
would cost two more runs and buy a number that the throughput ratio already
constrains. If the A2E transport profile becomes its own investigation later, that
is the right moment for it.
Nothing else from me blocks this on the code. #444 sequencing, the guide conflict,
the missing test-ready run and the absent decode data point are all stated in the
PR body, which is the right place for them.
e88eaae to
4851871
Compare
The synchronous CAMP2pAFDConnector had no way to quantize the A2E payload: the asynchronous CAM connector takes a dynamicQuant switch, this one shipped BF16 activations only. AFD's payoff comes from aggregating many attention instances onto fewer FFN instances, so that payload grows with the attention count and gets far more expensive once the two roles sit on different nodes. quant_mode=4 selects the new mode through connector_extra_config. The attention side quantizes the activation to E4M3 (or E5M2) with its E8M0 block scale and the A2E operator carries both; the FFN restores the model dtype, because the router reads the activation itself and the shared experts quantize their own input, so a model-dtype copy is needed regardless. Only the transport changes shape. The connector rejects mode 4 up front unless the operator accepts the new arguments and at least 3 AIV cores are configured, instead of failing later inside the kernel. Signed-off-by: 宋元盟 <songyuanmeng2@huawei.com>
The transport itself runs on hardware; these cover the decisions AFD makes around it, where a wrong answer is silent rather than loud: - the A5 rank shape the operator requires, asserted against the product's own limit rather than a copy that can drift; - the E8M0 exponent reconstruction in the receive path, pinned against scale bytes whose power of two is known by construction, including a hidden size that is not a multiple of the 32-element group -- a wrong bias here would only surface as accuracy drift on device; - quant_mode reaching the connector through connector_extra_config, and the values it rejects; - the send path padding the scale with the activation, and the receive path asking for both payloads; - deferred imports naming symbols that exist, which a CPU-only host cannot otherwise catch. tests/unit/.loc-baseline moves from 26423 to 26858: this feature adds 452 test lines against 1000 changed source, documentation and recipe lines, so the ratio rule in AGENTS.md holds. Signed-off-by: 宋元盟 <songyuanmeng2@huawei.com>
One A5 host, AFD 4A4F: attention DP4/TP1 on devices 0-3, FFN DP4/TP1 on devices 4-7. The entry records the measured configuration, the A/B numbers, and the two preconditions that are easy to get wrong: max-num-seqs is a per-rank limit, so the box only saturates at four times that in flight, and max-num-batched-tokens is a measurement setting whose only functional constraint is max(cudagraph_capture_sizes) < the chunk. It also records why the FFN restores BF16 rather than consuming the transported FP8, and that no non-AFD baseline was measured -- the comparison it would answer is described so it can be run, without a launch script carried in the tree. Signed-off-by: 宋元盟 <songyuanmeng2@huawei.com>
Record quant_mode=4 as the connector's single transport switch in the connector contract, the platform matrix and the user guide, including what the mode does not do (the FFN still restores the model dtype, because the router and the shared experts need one) and the load shape the measurement covers. Signed-off-by: 宋元盟 <songyuanmeng2@huawei.com>
4851871 to
2b34225
Compare
jiangkuaixue123
left a comment
There was a problem hiding this comment.
Static review at 2b34225. One additional E8M0 decoding issue below; no tests were executed.
| groups = int(scale.shape[-1]) | ||
|
|
||
| exponents = scale.view(torch.uint8).to(torch.int32) | ||
| scaling = (exponents << 23).view(torch.float32).to(torch.bfloat16) |
There was a problem hiding this comment.
[P2] Handle the two E8M0 endpoint encodings before shifting
E8M0 byte 0x00 represents 2^-127, not zero, and 0xff represents NaN, not infinity (see PyTorch's conversion). This shift therefore silently zeros a valid minimum-scale block: an E4M3 activation of 16 with scale byte 0 should restore to 2^-123, which is representable in BF16, but currently becomes 0. It also changes NaN-scale propagation. Please special-case these encodings in the reconstructed FP32 bits and cover bytes 0 and 255 in the dequantization tests.
Purpose
The synchronous
CAMP2pAFDConnectortransports the FFN activation as BF16 andoffers no quantization; the asynchronous connector has a
dynamicQuantswitch,this one does not. AFD's payoff comes from aggregating many attention instances
onto fewer FFN instances, so the payload shipped on this path grows with the A
count — and gets considerably more expensive once A and F are placed on different
nodes (see Potential for larger gains at scale below).
This PR adds the missing mode. On the attention side the activation is quantized
to FP8 (E4M3) plus an E8M0 block scale and transported in that form; the
block-scale transport comes from the operator support in #444. The FFN side
restores the model dtype at the module boundary, because two consumers there need
it: the router reads the activation itself (
MoeGatingTopKHash,x=router_logits) and the shared experts quantize their own inputunconditionally. Keeping that restore keeps the change confined to the transport.
Result: +34.5% total token throughput at 128 concurrent requests on one A5
host. Details, and the reason the gain is conditional, are in
Test Result.
Issue
Scope
quant_modeoption it already exposes through
connector_extra_config, the A5DeepSeek-V4-Flash recipe, and unit coverage.
a2eoperator itself — that is [WIP] feat(npu): support MXFP8 datatype for A2E operator #444. The operator files aredeliberately not duplicated here; this branch contains only the service
side.
Implementation Notes
connector_extra_config.quant_modegains a second value:0keeps the BF16transport (the default),
4moves a pre-quantized E4M3 activation plus itsE8M0 block scale. This is the connector's existing field, so there is no
additional switch and the two roles cannot drift apart through a second
configuration surface.
Mode 4 is rejected up front unless the A2E operator accepts
x_scaleandquant_modeand at least 3 AIV cores are configured, instead of failing laterinside the kernel.
The FFN restores the model dtype after the receive. This preserves the
existing router and shared-expert input path and keeps quantization confined to
the transport.
Direct FP8 consumption was evaluated and is excluded from this PR: it measured
6.8% lower throughput, added a per-layer collective for the transported scale,
kept both FP8 and BF16 activations resident, had incomplete scale propagation on
the DP=1 and SP/EP paths, and came in 1.59 GSM8K points below the baseline.
Details are under Why the FFN restores BF16; the
measurements are kept there to document the trade-off and guide future work.
Test Environment
Ascend950DT_9574CAMP2pAFDConnector, process-group rendezvous127.0.0.1:6239ced6857afa), vLLM-Ascend8d4409d62, plugin built from this branch plus the #444 operator--max-num-batched-tokens 3072,--max-num-seqs 128,--max-model-len 9216,--kv-cache-dtype fp8,attention-config {"indexer_kv_dtype":"fp8"},cudagraph_capture_sizes [8,16,32,64,128]withFULL_DECODE_ONLY,HCCL_BUFFSIZE 2048,PYTORCH_NPU_ALLOC_CONF expandable_segments:Falsevllm_api_general_chat+synthetic_gen: 128 requests, 8192 tokens in / 32 out,batch_size=128,RequestCount=128,temperature=0,ignore_eos=TrueThe gain depends on the load: the same configuration measured −0.3% at 8
concurrent requests, because each layer's round-trip wait is then dominated by its
fixed latency rather than by the activation payload. 128 concurrent is the load
this was validated at, not a threshold derived from the configuration —
--max-num-seqsis a capacity limit (128 per rank, so up to 512 in flight acrossDP4) and says nothing about when the box saturates.
On
--max-num-batched-tokens 3072. The default is 2048 and it is equallycorrect; mode 4 works at any chunk. 3072 was chosen for measurement because it is
the largest value at which all four DP ranks fill to the cap — at 4096 only the
first step reaches it and later steps fall to ~2500, which lowers throughput for
both configurations (measured below).
Test Plan
quant_modevaluesconnector_extra_configaccepts and rejects, the E8M0exponent reconstruction (including a hidden size that is not a multiple of the
32-element group), the send path padding the scale with the activation, the
receive path requesting both payloads, and deferred imports naming symbols that
exist.
quant_mode=0versus4at 128 concurrentrequests, two runs each, plus GSM8K and an A-side torch profiler trace.
Test Result
Throughput — chunk 3072, 128 concurrent, two runs each
quant_mode=0(BF16 transport)quant_mode=4(MXFP8)Failed Requests = 0andMax Concurrency = 128in all four runs. Gain overquant_mode=0: +34.7%.Re-validated after rebasing onto
main(2026-10-20, two runs each)quant_mode=0quant_mode=4Gain: +34.5%. Both sides drifted by about 2.5% relative to the first table and
in the same direction. With two runs per group that is not enough to call the
result unchanged; what it does show is that the mean throughput gain remained
similar after rebasing.
chunk 4096 (one run each)
quant_mode=0quant_mode=4+35.9%. The ratio holds, but both absolute numbers are below the chunk-3072 runs,
which is why 3072 is the configuration in the recipe.
Where the time goes (A-side torch profiler, chunk 3072)
E2a— the receive that blocks the attention side for the whole FFN round trip —accounts for 49.5% of attention-side device time with the BF16 transport. That
is where the saving has to appear, not in
A2e: the A-side send isfire-and-forget (it writes its own window and an 8-byte flag), so it never waits
on the payload.
The two traces were captured over different step counts, so their per-call totals
are not comparable and this PR does not claim a per-operator delta from them. The
share above is the one number that is stable across both.
Accuracy (GSM8K,
max_out_len=2048,ignore_eos=False,batch_size=8)quant_mode=0quant_mode=4quant_mode=4, earlier configurationAbout −0.15 points against a ±0.5 point spread on this benchmark; the same path
measured 92.87% once, so do not call it lossless. A 0.15-point move is inside
the spread at this sample size, and the third row shows the spread is real.
Unit tests
The added coverage is targeted rather than bulk: the operator capability probe
(supported, unsupported, not loaded), the send and receive call shapes — including
that
quant_mode=0still passes the original twelve arguments — the E8M0reconstruction with a hidden size that is not a multiple of the 32-element group,
and the deferred-import surface.
tests/unitno longer carries a line budget;#474 removed that gate upstream, so this PR neither moves nor relies on it.
Scope of the run. The CPU-only run was on a host without
torch_npuor ausable vLLM, so the tests that need either were skipped, not passed. They were
later executed on an A5 host:
tests/unit/connectors/test_camp2p_connector.pyreported 20 passed, which covers the operator probe, both send call shapes and
the receive dequantization. The four failures that remain (three in
test_ascend_config_lifecycle.py, plustest_package.py::test_entry_point_is_registered) also fail onmainin the sameenvironment, so they are pre-existing rather than introduced here.
Device validation, against a build whose
a2eoperator predates the MXFP8arguments (
len(schema.arguments) == 12, soa2e_accepts_mxfp8_arguments()isFalse):quant_mode=0, both roles/v1/completionscall, so the whole send/receive path works on the twelve-argument call — the backward-compatibility claim this PR makes for the default modequant_mode=4, F roleA2E MXFP8 needs an a2e operator that accepts x_scale and quant_mode, before any device work — the capability probe reads the real extension, not a mockStill open: the positive case. #444 has to land so a build accepts the pair; then
construction should succeed and mode 4 should run. The only CI check on this PR is
DCO.
Why the FFN restores BF16
The FFN restores the transported MXFP8 activation to BF16 before running MoE.
This preserves the existing router and shared-expert input path while keeping
quantization confined to A2E transport.
Direct FP8 consumption was evaluated but excluded from this PR. This variant
let routed experts reuse the transported FP8 activation and scale, skipping
internal re-quantization. It achieved 296,934 token/s versus 318,519 token/s for
the BF16-restoring path — 6.8% lower throughput.
Avoiding re-quantization introduced other costs. On the DP all-gather path, the
transported scale required its own pad-and-gather operation to stay aligned with
the gathered activation, adding one collective per layer. The variant also
retained both FP8 and BF16 activations: routed experts consumed FP8, while the
router still required BF16. These costs can offset the computation saved, although
their individual contributions to the slowdown were not isolated.
The implementation also had incomplete scale propagation for DP=1 and SP/EP paths.
GSM8K accuracy was 92.27%, compared with 93.86% for the BF16 baseline, a
1.59-percentage-point drop requiring further investigation; the result alone does
not establish the cause.
The PR therefore retains the BF16-restoring path. The direct-path measurements are
recorded here to document the trade-off and guide future work.
Potential for larger gains at scale with suitable A/F ratios and interconnects
All results above were measured on a single eight-device host, with Attention and
FFN communicating over the intra-node HCCL fabric. These measurements establish
the benefit in that configuration; larger deployments introduce two additional
factors that may increase the value of A2E quantization.
Higher A:F ratios can put greater pressure on the A2E path. One motivation
for AFD is to let multiple Attention instances feed fewer FFN instances,
combining distributed KV-cache capacity with larger batches for expert
computation. As more Attention instances contribute tokens, both the incoming
activation volume and the FFN workload increase. If FFN computation remains
efficient while activation delivery becomes a bottleneck, reducing A2E traffic
can help sustain the benefit of aggregation.
Bandwidth-constrained links can make payload reduction more valuable. When
A/F placement requires traffic to cross a lower-bandwidth interconnect,
transferring the same activations takes longer and consumes a larger share of the
available link capacity. MXFP8 roughly halves the activation-data portion of A2E
traffic relative to BF16, although scale metadata and other communication costs
remain. The resulting benefit may therefore be greater when A2E bandwidth is a
limiting resource.
These are expectations, not measured results. In the single-host experiment, E2A
accounted for 49.5% of Attention-side device time, and the measured throughput
improvement was +34.5%. That device-time share is not, by itself, an end-to-end
bottleneck measurement. Nevertheless, larger gains are plausible if higher A:F
ratios and more bandwidth-constrained links make A2E transfer a greater part of
the critical path, provided quantization overhead and other bottlenecks do not
offset the savings. Validating this expectation requires measurements across
deployment scales, A/F ratios, and interconnect configurations.
What this PR does not cover
recipe README says the same. A decode data point needs its own run.
fabric here.
Docs Impact
docs/npu/CAM_P2P_CONNECTOR_USER_GUIDE.md:quant_modedocumented as thesingle transport switch, with what the mode does and does not change. The
transport section builds on text already in [WIP] feat(npu): support MXFP8 datatype for A2E operator #444, so it should be rebased after
that PR lands.
docs/design/module/connector_contracts.mdandexecution_platforms.md: theaccepted
quant_modevalues, their prerequisites, and the load shape themeasurement covers.
recipe/npu/CAMP2pAFDConnector/deepseek_v4_flash/: the measured configuration, the A/B numbers, and what the measurement depends on. No launch script is carried in the tree.