AkiYang推理工程手记

Ascend 910C 投机解码Graph、多流与通信的执行依赖

· 源码核对 2026-09-21
版本与源码依据
系列阅读 · DeepSeek-V4 投机解码展开篇目
本页目录

在 Ascend 910C 上,一轮投机解码会经过 Draft、Verify、Accept 和状态提交。Graph Replay 可以减少重复提交开销,多流可以重叠独立工作,但候选依赖、缓存准备和通信等待仍会约束下一步何时开始。

本文沿 DeepSeek-V4 的 EAGLE/NextN 路径标出这些依赖:图里捕获了哪些 forward,Plan Stream 能与谁重叠,DeepEP 的等待点在哪里。源码可以确定执行关系;哪一段成为实际关键路径,还要把设备时间线与这些关系对齐。

源码版本与阅读范围

源码基线:本文固定基于 sgl-project/sglang @ 5c69e32abe013fa1b913022682a3104c79105f37,核对日期为 2026-09-21。主线讨论 DeepSeek-V4 + EAGLE / NextN + Ascend 910C + dsv4 backend。图中展示由 Stream、Event、Wait 和 Graph 调用推导的依赖关系;耗时与重叠比例由设备时间线测量。

一、Graph、Stream 与通信各自负责什么

Graph、Stream 与通信分别处理不同的执行成本。先看它们在一轮 EAGLE 中的位置:

机制 本文对应的执行方式
Draft Graph 捕获完整 draft_forward(),执行 num_steps - 1 次 NextN Forward
Verify Graph 按请求数选择档位,每请求保留固定 Verify 宽度
Plan Stream Verify Prep 等待 Draft;Draft-Extend Prep 可与已提交的主流尾部重叠
Target 多流 重叠 Q、KV 与 Indexer 等独立工作;NextN 未接入这组 alt streams
DeepEP 异步通信 分开发起与等待,在中间安排独立计算
Draft-Extend Graph 用重复启动成本的节省,交换捕获与 workspace 内存开销

后文依次展开捕获宽度、等待位置和配置入口。

把六个结论放在一起,可以先得到一轮稳态 EAGLE 的骨架:

上一轮 confirmed state
        │
        ▼
Draft Graph
(num_steps - 1 次 NextN forward)
        │
        ▼
Verify Planning
        │
        ▼
Target Verify Graph
        │
        ▼
Accept / Commit
        │
        ├──────── Draft-Extend Planning
        │           可与 main-stream tail overlap
        ▼
Draft Extend Forward / Graph
        │
        ▼
下一轮 candidate1

优化问题因此变成:

每一个 Fork 最后在哪里 Join?哪条 branch 最长?哪些 communication / planning 已经被其他工作覆盖,哪些仍然暴露在 Critical Path 上?

二、Draft Graph 捕获哪些 NextN Forward

DeepSeek-V4 的 EAGLE Draft 在 NPU 上有专门 Runner:EAGLEDraftNpuGraphRunner

固定源码:

eagle_draft_npu_graph_runner.py

它继承通用 EAGLEDraftCudaGraphRunner,但在 NPU 路径上底层使用的是 torch.npu.NPUGraph。这里沿用历史 CUDA 类名,底层运行的是 NPU Graph。

从 Capture Body 可以数清捕获的 Forward 次数。

EAGLEDraftCudaGraphRunner.capture_one_shape() 最终捕获:

def run_once():
    ...
    ret = self.eagle_worker.draft_forward(
        forward_batch
    )
    ...
    return ret

也就是说,一次 Draft Graph Replay 包住的是整个 draft_forward(),而不是单独某一次 draft_runner.forward()。

固定源码:

EAGLEDraftCudaGraphRunner.capture_one_shape()

draft_forward() 的 NextN Forward 次数

主循环:

for i in range(self.speculative_num_steps):
    ...
    select_top_k_tokens(...)

    if i == self.speculative_num_steps - 1:
        break

    logits_output = self.draft_runner.forward(
        forward_batch
    ).logits_output

固定入口:

EagleDraftWorker.draft_forward()

对应计数为:

NextN model forward count inside Draft Graph
=
speculative_num_steps - 1

例如官方常见:

num_steps = 2
topk = 1
num_draft_tokens = 3

这一轮 Draft Graph 实际是:

进入 Graph 前:
candidate1 已由上一轮 Draft Extend 准备好

Graph Replay:
candidate1
    ↓
1 × NextN forward
    ↓
candidate2
    ↓
organize draft result

不是两次 NextN forward。

如果 num_steps=3,则是:

candidate1
    ↓
NextN forward #1
    ↓
candidate2
    ↓
NextN forward #2
    ↓
candidate3

Graph Capture 覆盖完整 rollout,其中候选阶段数与模型 Forward 次数分别为:

candidate stage 数 = num_steps

真正的 NextN model forward 数 = num_steps - 1

第一枚 candidate 的成本属于上一轮 Draft Extend,而不是这一轮 Draft Graph。

Draft Graph 的静态宽度是什么

Draft Decode 的 per-request width 统一由:

resolve_num_tokens_per_req(
    phase="draft_decode"
)

解析为:speculative_eagle_topk

固定源码:

resolve_num_tokens_per_req()

因此当前官方 topk=1 时,一次 NextN Draft forward 的输入宽度是 1 token / request,但 Graph body 内会执行 num_steps-1 次 NextN forward。

这正是 Graph 对轻量 Draft 特别有价值的原因:

NextN compute 很轻
        ↓
固定 Python / launch / metadata overhead
占比容易变高
        ↓
Capture 整个小循环
比只优化某个单独 kernel 更有意义

Graph/Eager 选择本身也可能是分布式一致性状态

EAGLEDraftNpuGraphRunner.can_run_graph() 在特定 DSA IndexShare + DP Attention 场景下,会把本地 can_run_graph && seed_ready 做成一个整数,然后对 model TP group:

torch.distributed.all_reduce(
    decision,
    op=MIN,
    group=tp_group,
)

原因是 Draft forward 里仍包含 TP / EP collective。

如果同一个 distributed forward 中出现:

Rank0 → Graph
Rank1 → Eager

collective 调用次序可能失去一致性。

因此:

Graph/Eager route 本身也可能属于 speculative control plane,必须在协作 Rank 间收敛。

三、Verify Graph 的 Batch Bucket 与 Token 宽度

Draft 完成以后,Target Verify 会进入通用 DecodeCudaGraphRunner / NPUGraphRunner。

固定 NPU 入口:

NPUGraphRunner

Target Runner 初始化时:

self.captured_req_width
=
model_runner.decode_num_tokens_per_req(
    num_draft_tokens=...
)

对于普通 EAGLE Target:

captured_req_width
=
speculative_num_draft_tokens

固定来源:

因此如果 num_draft_tokens=3,每个请求 Target Verify 的 Graph 宽度固定是 3 rows。

当前 EAGLE 不是 Ragged Verify

这一点必须和 DSpark 区分。

SpeculativeAlgorithm.supports_ragged_verify() 在固定版本中:

return self.is_dspark()

固定源码:

spec_info.py

所以当前 EAGLE / NextN Target Verify 不是:

Req0 verify 2 tokens
Req1 verify 3 tokens
Req2 verify 1 token
        ↓
按 sum(verify_lens) 选择 token bucket

而是每个 request 固定 Verify num_draft_tokens rows。

Accept Length 在 Verify 之后产生,因此本轮 EAGLE Verify 仍按捕获的固定宽度执行,接受较短只影响后续提交。

普通 EAGLE Graph 首先按 Request Batch Size 选 Bucket

非 Ragged path 的 load_batch():

raw_num_token
=
raw_bs * captured_req_width

bs
=
_pad_to_bucket(
    raw_bs,
    capture_bs,
)

padded_num_tokens
=
bs * captured_req_width

固定源码:

DecodeCudaGraphRunner.load_batch()

假设:

raw_bs = 5
num_draft_tokens = 3

Graph request buckets:
1, 2, 4, 8

则:

真实 Verify rows = 5 × 3 = 15

Graph bucket = 8 requests

Graph replay rows = 8 × 3 = 24

其中 9 rows 来自 bucket padding。

所以 Graph 的收益和代价同时存在:

收益:
减少 launch / Python / control overhead

代价:
执行 padded request slots 对应的额外 token rows

DP Attention 下 admission 甚至不是本 Rank 的 raw_bs

如果需要 MLP TP gather,can_run_graph() 会用:

cuda_graph_bs
=
max(
    forward_batch.original_global_num_tokens_cpu
)

也就是 Attention-DP 各 Rank 原始 request count 的最大值。

随后相关 Rank 进入兼容这个 global-max geometry 的 Graph bucket。

因此对 DP Attention + Speculation,Graph padding 还承担一个分布式目的:

让协作 Rank 在同一 captured collective geometry 上 replay。

分析 Target Verify Graph 时,将本地请求数与下面几项一起核对:

DP group 最大 Request Count
×
固定 Verify Width
×
Capture Bucket

--cuda-graph-bs-decode 在这里是 Request Bucket,不是 EAGLE Verify Token Bucket

固定 DeepSeek-V4 Ascend best-practice 中可以看到:--cuda-graph-bs-decode 1 2 4 8

或:1 2 4 8 10

在当前普通 EAGLE 路径里,这些 key 首先表示 captured request slots。

若 num_draft_tokens=3,Target Verify 对应的 token rows 才是:bucket_bs × 3

DSpark Ragged Verify 则按 graph_num_tokens tier 组织工作,相关成本模型在 DSpark 专题中展开。

四、Plan Stream 与计算的依赖关系

环境变量:SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1

会创建:

plan_stream
=
torch.get_device_module(device).Stream()

固定源码:

get_plan_stream()

但“有第二条 Stream”并不意味着任何两个阶段真的在设备上并行。

关键要看 wait_stream 在哪里。

Verify Planning 等待 Draft 结果

run_eagle_verify() 一开始拿到当前 compute stream:

fwd_stream = current_stream()

随后:

with plan_stream_ctx:
    plan_stream.wait_stream(
        fwd_stream
    )

    eagle_prepare_for_verify(...)

源码注释明确说明:Verify Prep 会读取 Draft 生成的 Tree metadata,因此不能在 Draft frontier 完成以前开始。

Plan 完成后,main stream 又:

current_stream().wait_stream(
    plan_stream
)

才启动 Target Verify。

固定源码:

run_eagle_verify()

Device dependency 实际是:

Main Stream
Draft
████████████
            │
            ▼

Plan Stream
            Verify Plan
            ███████
                   │
                   ▼

Main Stream
                   Target Verify
                   ███████████████

因此不存在 Draft Compute 与 Verify Planning 的设备重叠。

Plan Stream 在这里的意义更接近:

  • 把 planning device work 放到独立 stream;
  • 减少不必要的 Host blocking;
  • 明确 metadata ownership;
  • 用 Stream dependency 而不是 Host 同步表达执行顺序。

但真实的数据依赖仍然位于 critical path。

Draft-Extend Planning:这里反而真的可以跨阶段 overlap

Verify 完成后,_draft_extend_for_decode() 先构造 EagleDraftExtendInput、select_index 和 next_token_ids,然后直接:

with self.plan_stream_ctx:
    forward_batch = prepare_for_draft_extend(...)

注意这里在 planning 之前没有:

plan_stream.wait_stream(
    current_stream
)

固定源码:

_draft_extend_for_decode()

Python 从 run_eagle_verify() 返回,并不表示之前 enqueue 的 NPU kernels 已经执行完成。设备执行是异步的,因此 Plan Stream 上的 Draft-Extend Planning 可以与 Main Stream 上尚未完成的 Target Verify / Accept tail 形成并发,只要 Planning 本身不读取那些尚未 ready 的 Device value。

源码还专门把:

next_token_ids
=
batch_result.next_token_ids.to(torch.int64)

放在进入 Plan Stream 之前,并写明这是为了避免在 Plan Stream 内发生额外 cross-stream synchronization / data race。

随后进入 Draft Extend Forward 前:

current_stream().wait_stream(
    self.plan_stream
)

因此更准确的 Timeline 是:

Main Stream
Target Verify
████████████████
        Accept kernels
        ████████
                │

Plan Stream
        Draft-Extend Planning
        ███████████
                │

Main Stream
                wait(plan)
                    │
                    ▼
             Draft Extend Forward
             ███████████

两种 Planning 的依赖分别是:

Verify Prep:
Draft → Plan → Verify
严格依赖

Draft-Extend Prep:
Target Verify / Accept main-stream tail
        ∥
Draft-Extend Planning
        ↓
Join
        ↓
Draft Extend Compute

五、Target 与 Draft 的多流路径

SGLANG_NPU_USE_MULTI_STREAM=1 控制 DeepSeek-V4 单个模型 Layer 内部的局部并行。Plan Stream 处理投机阶段的计划工作,两者的作用范围不同。

Target DeepSeek-V4 Model 初始化时,只要 NPU 环境变量开启,就创建一组 alt_streams,并把它传进每个 DeepseekV4DecoderLayer。

固定源码:

DeepseekV4Model.__init__()

Attention Layer 收到 alt streams 后,NPU eligibility 是:

_is_npu
and SGLANG_NPU_USE_MULTI_STREAM
and self.alt_streams is not None
and x.shape[0] <= self._multi_stream_bs_limit
and not forward_batch.forward_mode
    .is_extend_or_draft_extend_or_mixed()

固定源码:

DeepSeek-V4 Attention forward

这里有两个容易误读的地方。

TARGET_VERIFY 没有被排除

ForwardMode.is_extend() 确实把 TARGET_VERIFY 看成 extend-family。

但 Multi-Stream 条件调用的不是 is_extend(),而是:is_extend_or_draft_extend_or_mixed()

这个 helper 的默认参数:include_draft_extend_v2 = False

所以默认只排除:

EXTEND
MIXED
SPLIT_PREFILL

并不排除 TARGET_VERIFY。

固定源码:

ForwardMode

所以 Target Model 的:

DECODE
TARGET_VERIFY

都可以满足 mode 这一层条件。

DRAFT_EXTEND_V2 也没有被 helper 默认排除,但 NextN 自己没有 alt streams

更反直觉的是,DRAFT_EXTEND_V2 在默认参数下也不被这个 helper 排除。

ForwardMode 之外,还要检查模型是否创建并传入 alt streams。

但 DeepSeek-V4 NextN Model 构造唯一 decoder layer 时显式:

self.decoder = DeepseekV4DecoderLayer(
    ...,
    alt_streams=None,
    ...
)

固定源码:

deepseek_v4_nextn.py

所以 NextN layer 内 self.alt_streams=None。

最终实际可达性是:

Phase ForwardMode Model Attention NPU Multi-Stream
普通 Target Decode DECODE Target 可达,还需 env / token rows / layer 条件满足
EAGLE Target Verify TARGET_VERIFY Target 可达
EAGLE Draft Decode DECODE NextN 不可达,NextN decoder 的 alt_streams=None
EAGLE Draft Extend DRAFT_EXTEND_V2 NextN 不可达,同上
普通 Prefill EXTEND Target 该 NPU Attention Multi-Stream path 被 mode 条件排除

Target 多流中的独立计算分支

进入 _forward_prepare_multi_stream_npu() 后:

stream_kv
→ KV projection / Norm / RoPE / KV cache store

stream_q
→ Q projection / RMSNorm / RoPE

current stream
→ Indexer / Compressor

最后:

current_stream.wait_stream(stream_kv)
current_stream.wait_stream(stream_q)

才进入 downstream Attention。

固定源码:

_forward_prepare_multi_stream_npu()

因此局部 Critical Path 理想模型更接近:

T_prepare
≈
T_prefix
+
max(
  T_Q,
  T_KV,
  T_indexer/compressor
)

而不是三者相加。

这些分支可并发提交,实际重叠程度随 Cube / Vector 资源竞争、HBM 带宽、Kernel Occupancy、CANN 调度与 Token 行数变化。用 Profiler 对齐开始、结束与汇合点,就能量出其中暴露的等待。

另外固定源码中非 Blackwell 的 Multi-Stream row limit 是 64。这里判断的是当前 Layer 的 x.shape[0],不是服务器的 max_running_requests。

六、DeepEP 从异步 Launch 到等待结果

DeepSeek-V4 Target Verify 还会进入 MoE。

官方 Ascend recipe 使用:

--moe-a2a-backend deepep
--deepep-mode auto

FusedMoE 创建 DeepEP dispatcher 时传入:

async_finish=True
return_recv_hook=True

固定入口:

fused_moe_triton/layer.py

但这两个参数并不意味着:

Dispatch
∥
Routed Expert GEMM

天然并行。

Normal DeepEP:通信异步 Launch,但 Expert 前仍必须 Wait

Normal dispatcher:

previous_event = Buffer.capture()

buffer.dispatch(
    ...,
    async_finish=True,
    allocate_on_comm_stream=True,
)

通信可以在 Communication Stream 上启动。

但 dispatch_b() 随后:

event.current_stream_wait()

然后才返回 Expert 输入。

固定源码:

_DeepEPDispatcherImplNormal

因此真实依赖仍然是:

DeepEP Dispatch
        ↓
recv complete barrier
        ↓
Routed Expert GEMM

async_finish=True 将 Launch 与 Wait 分开;Routed Expert 仍在接收完成后开始计算。

Combine 也是同样结构:

Combine async launch
        ↓
event.current_stream_wait()
        ↓
combined hidden consumer

所以 Normal mode 的 async API 主要提供:

把 communication 放到 communication stream 执行的能力;能隐藏多少,取决于 Wait 之前有没有别的 independent work。

Shared Expert 正好是一个独立 branch

DeepSeek MoE 在 Shared Expert 没有 fuse 到 routed path 时,可以把 Shared Expert 放到 alt stream:

self.alt_stream.wait_stream(
    current_stream
)

with alt_stream:
    shared_output
    =
    _forward_shared_experts(...)

随后主路径继续:

TopK
→ DeepEP Dispatch
→ Routed Experts
→ Combine

最终再等待 Shared Expert output。

固定源码:

DeepseekV2MoE.forward_deepep()

因此可能形成:

Routed path
Router
  ↓
Dispatch ───────── Expert ───── Combine
██████████████████████████████████████

Shared side stream
Shared Expert
████████████████

这里 Shared Expert 可以覆盖 Routed Path 的一部分时间,其中也可能包含 Communication。

对齐耗时时,同时记录 DeepEP 总时长与以下等待:

通信结束以后
还有多少 Tail
没有被 independent compute 覆盖

Low-Latency DeepEP:recv_hook 把 Wait 推迟到 Consumer Boundary

Low-latency dispatch 调用:

buffer.low_latency_dispatch(
    ...,
    async_finish=False,
    return_recv_hook=True,
)

得到:

event
hook

外层 DeepEPDispatcher.dispatch() 的顺序是:

dispatch_a()
    ↓
deepep_dispatch_hooks
    ↓
dispatch_b()

而 Low-Latency dispatch_b():

hook()

才等待 / 完成接收。

固定源码:

_DeepEPDispatcherImplLowLatency

这提供了一个真实 overlap slot:

low_latency_dispatch launch
        ↓
[ dispatch hook 可执行 independent work ]
        ↓
recv_hook()
        ↓
Expert consumes received tokens

SBO 路径正是利用这个 slot,把 Shared Expert 等独立计算放进 Communication 等待窗口。

recv_hook 将等待留到接收数据被消费的位置:

把 Wait Point 从 Communication Launch 处推迟到消费 recv buffer 的边界,让中间可以插入与 recv 数据无关的 Compute。

Combine 侧也是同样思想;有 overlap_args 时 Low-Latency combine 可以切到 overlap stream,最终仍在 Consumer Boundary Join。

应该看 Exposed Communication,不是 Total Communication

如果某段 Communication 时间是 T_comm,同时独立计算能覆盖 T_independent,理想情况下暴露在 Critical Path 上的是:

T_exposed_comm
=
max(
  0,
  T_comm - T_independent
)

如果 async launch 后立刻 Wait:T_independent = 0

那么:T_exposed_comm ≈ T_comm

所以“async”并不自动带来性能收益。

七、Draft-Extend Graph 的配置与版本差异

固定版本 Ascend DeepSeek-V4 best-practice 中,部分 workload 可以看到:

export SGLANG_DISABLE_DRAFT_EXTEND_GRAPH=1

同时还开启:

export SGLANG_ENABLE_OVERLAP_PLAN_STREAM=1
export SGLANG_NPU_USE_MULTI_STREAM=1

并使用 EAGLE、NPU Graph 和 DeepEP。

第一眼很容易解释成:

“这个 workload 实测发现 Draft Extend Graph 更慢,所以官方关闭。”

实际调用路径还需要进一步区分。

Runtime 读取的环境变量名

固定 environ.py 注册的是:SGLANG_DISABLE_DRAFT_EXTEND_CUDA_GRAPH

其源码注释:

Kill-switch for draft-extend cuda graph. Escape hatch for setups where the capture's memory pool costs more than the graph saves, e.g. DeepEP MoE workspace captured at full dispatch capacity.

固定源码:

environ.py

EAGLE Worker 创建 Draft-Extend Graph 时检查的也是:

not envs
    .SGLANG_DISABLE_DRAFT_EXTEND_CUDA_GRAPH
    .get()

固定入口:

EagleDraftWorker._capture_cuda_graphs()

但固定版本 best-practice 页面写的是:SGLANG_DISABLE_DRAFT_EXTEND_GRAPH

少了 _CUDA_。

在这个 commit 的仓库里没有找到旧名字对应的 EnvBoolWithAlias、consumer 或 translation。

因此这条文档配置存在明显的:doc / runtime env-name drift

该版本应使用 Runtime 读取的 SGLANG_DISABLE_DRAFT_EXTEND_CUDA_GRAPH 控制开关。部署脚本若沿用旧名,需要在启动日志中检查实际 Graph 状态。

但“为什么需要这个 Kill Switch”有明确源码依据

正确 Runtime flag 的注释已经给出设计动机:

Draft-Extend Graph Capture
        ↓
静态 memory pool / workspace
        ↓
某些 MoE / DeepEP workspace
按 full dispatch capacity 捕获
        ↓
常驻 footprint 变大
        ↓
Graph 节省的 launch latency
可能不值这份 memory cost

Draft Extend 本身又只是 NextN 的一段相对短 Forward。

所以它容易落入这样的 Trade-off:

Graph benefit
=
saved launch/control overhead
-
capture memory cost
-
padding cost
-
replay preparation cost

当:

Draft Extend compute 很短
+
DeepEP workspace capture 很大

时:

Draft Decode Graph       ON
Target Verify Graph      ON
Draft Extend             Eager

完全可能是合理 operating point。

但要强调:

这是 Runtime Kill-Switch 的设计动机,不是对固定 best-practice 那个旧变量名已经生效的证明。

Draft-Extend Graph 自己也有独立静态宽度

它的 Graph Runner EAGLEDraftExtendCudaGraphRunner 不是按 num_steps + 1 捕获。

源码明确:

captured_req_width
=
resolve_num_tokens_per_req(
    phase="draft_extend"
)

也就是:speculative_num_draft_tokens

固定源码:

EAGLEDraftExtendCudaGraphRunner

这意味着即使最终 accept_lens 较短,Draft Extend Graph 的 Buffer / Capture Geometry 仍按照完整 speculative width 设计; LM Head 只在 selected last-accepted rows 上做后续处理。

评估 Draft-Extend Graph 时,将捕获和 workspace 的内存开销与实际节省的启动时间一起比较。

八、将执行依赖与实测时间线对齐

下图只表达阶段依赖,不按长度表示耗时。实际重叠范围需要与 Profiler 时间线对照。

flowchart TD
    D["Draft 完成"] --> VP["Verify Plan"]
    VP --> V["Host 提交 Verify 与 Accept"]
    V --> A["Main Stream 执行验证与接受"]
    V --> EP["Plan Stream 准备 Draft Extend"]
    A --> J["所需结果与 Plan 就绪"]
    EP --> J
    J --> E["Draft Extend"]
层内分支 独立工作 汇合依赖
Target Attention Q、KV、Indexer / Compressor 的对应分支 Attention 消费前等待所需结果
Routed MoE Dispatch、Expert GEMM、Combine GEMM 等待收到 Token;后续消费等待 Combine
Shared Expert 可独立执行的专家计算 与 routed 输出合并前完成

Plan Stream 是否形成跨阶段重叠,取决于调用与等待位置。NextN Draft 没有接入这组 alt streams,使用自身的执行路径。

拿 Ascend Profiler 分析一轮 speculative decode 时,可以按这个顺序看:

观察点 对应源码问题
Draft Graph replay 还是 eager?num_steps 对应几次 NextN forward?
Draft Graph raw request count pad 到哪个 bucket?
Verify seam Draft 结束到 Verify start 中间,Verify Plan gap 多长?这段不能与 Draft overlap。
Target Verify 固定 Verify width 是多少?bucket_bs × num_draft_tokens 有多少 padding rows?
Plan overlap Draft-Extend Plan 是否真的与 Verify / Accept tail 同时出现在 NPU timeline?
Attention Q / KV / Indexer 三条 branch 哪条最长?Multi-Stream Join 最终等谁?
MoE DeepEP 总 duration 中,有多少被 Shared Expert / SBO 覆盖? exposed tail 是多少?
Rank control 是否因为某 Rank Graph fallback 导致整个 TP group 一起 eager?
Draft Extend Graph 还是 eager?Capture memory / workspace 是否值得?

把一轮时间线对齐以后,再用有效输出量衡量收益:同一批次条件下,每个输出 Token 的平均成本约为本轮关键路径耗时除以有效推进长度。Graph 减少启动与控制开销,多流利用独立工作,异步通信将等待推迟到消费边界;这些机制能否缩短周期,要看最终汇合点仍在等待谁。

记录实验时,将候选宽度、图档位、接受长度与依赖等待一起保留。只看 acceptance rate,或者把各 Stream 的耗时直接相加,都会遗漏影响端到端性能的部分。

源码阅读入口

目标 固定版本源码
EAGLE Worker eagle_worker_v2.py
Draft NPU Graph Runner EAGLEDraftNpuGraphRunner
Draft Graph Capture Body EAGLEDraftCudaGraphRunner
Draft Multi-Step Loop EagleDraftWorker.draft_forward()
Spec Phase Static Width resolve_num_tokens_per_req()
Target NPU Graph NPUGraphRunner
Target Graph Fixed Width / Bucket DecodeCudaGraphRunner
EAGLE / DSpark Ragged Verify 边界 SpeculativeAlgorithm.supports_ragged_verify()
Verify Preparation eagle_prepare_for_verify()
Verify + Plan Stream Dependency run_eagle_verify()
Plan Stream Creation get_plan_stream()
Draft-Extend Planning Overlap _draft_extend_for_decode()
Draft-Extend NPU Graph EAGLEDraftExtendNpuGraphRunner
Draft-Extend Graph Buffer / Width EAGLEDraftExtendCudaGraphRunner
Target NPU Multi-Stream Pool DeepseekV4Model.__init__()
NPU Attention Multi-Stream _forward_prepare_multi_stream_npu()
NextN Explicit alt_streams=None deepseek_v4_nextn.py
ForwardMode Boundary ForwardMode
DeepEP Normal Async Boundary _DeepEPDispatcherImplNormal
DeepEP Low-Latency Recv Hook _DeepEPDispatcherImplLowLatency
DeepSeek Shared-Expert Overlap DeepseekV2MoE.forward_deepep()
Draft-Extend Graph Kill Switch environ.py
Ascend DeepSeek-V4 Best Practice deepseek_v4_flash.mdx
返回阅读地图 →
读到这里

从一条请求,看见整个系统。

返回文章目录

本页目录

搜索文章与 Skills

↑ ↓ 选择 · Enter 打开 · Esc 关闭 · Ctrl / ⌘ K 搜索

工程图