Initial commit
This commit is contained in:
@@ -0,0 +1,427 @@
|
||||
# 方向3: 加速器协同调度 (CPU + NPU/GPU)
|
||||
|
||||
## 1. 问题陈述
|
||||
|
||||
现代嵌入式AI SoC都包含专用加速器(NPU/GPU/DSP),LLM推理需要CPU和加速器协同工作。核心问题:
|
||||
|
||||
1. **速度不匹配**: CPU和加速器的速度比通常是1:5~1:10,容易产生stall
|
||||
2. **状态不可见**: NPU驱动通常封闭,无法精确感知NPU状态
|
||||
3. **数据传输开销**: CPU↔NPU的数据传输是瓶颈
|
||||
4. **同步开销**: barrier/semaphore的实时性分析复杂
|
||||
|
||||
## 2. 加速器架构分析
|
||||
|
||||
### 2.1 常见加速器类型
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Accelerator Types │
|
||||
├──────────────────┬───────────────────────────────────┤
|
||||
│ NPU │ Neural Processing Unit │
|
||||
│ │ • 专为矩阵乘设计 │
|
||||
│ │ • 低精度(INT8/FP16) │
|
||||
│ │ • 固定function, 可编程interface │
|
||||
│ │ 例: 骁龙Hexagon, RK3588 NPU │
|
||||
├──────────────────┼───────────────────────────────────┤
|
||||
│ GPU │ Graphics Processing Unit │
|
||||
│ │ • 通用并行计算 │
|
||||
│ │ • 高带宽, 高功耗 │
|
||||
│ │ • 成熟软件栈(CUDA/OpenCL) │
|
||||
│ │ 例: Adreno, Mali, PowerVR │
|
||||
├──────────────────┼───────────────────────────────────┤
|
||||
│ DSP │ Digital Signal Processor │
|
||||
│ │ • 向量/标量并行 │
|
||||
│ │ • 低功耗, 适合小模型 │
|
||||
│ │ 例: Hexagon DSP, Kryo │
|
||||
├──────────────────┼───────────────────────────────────┤
|
||||
│ DPU │ Deep Learning Processing Unit │
|
||||
│ │ • 固定功能, 低延迟 │
|
||||
│ │ • 适合known architecture │
|
||||
│ │ 例: Xilinx DPU, 平头哥玄铁 │
|
||||
└──────────────────┴───────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 CPU-加速器通信路径
|
||||
|
||||
```
|
||||
CPU Accelerator
|
||||
┌─────────────┐ ┌──────────────┐
|
||||
│ │ DMA/Bus │ │
|
||||
│ Task Queue │─────────────→│ Command Q │
|
||||
│ │ │ │
|
||||
│ Memory │←──DMA/Bus───│ Memory │
|
||||
│ Pool │ │ Pool │
|
||||
│ │ │ │
|
||||
│ Event Q │←────────────│ Interrupt │
|
||||
└─────────────┘ └──────────────┘
|
||||
|
||||
通信机制:
|
||||
1. Shared Memory: 零拷贝,通过DMA传递数据
|
||||
2. Command Queue: CPU写入命令,加速器执行后完成
|
||||
3. Interrupt: 加速器完成后的异步通知
|
||||
4. Memory Barrier: 保证CPU和加速器看到的内存一致性
|
||||
```
|
||||
|
||||
## 3. 协同调度模型
|
||||
|
||||
### 3.1 典型LLM推理的CPU-加速器交互
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Phase: Prefill (Batch Inference) │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ CPU: Accelerator: │
|
||||
│ ┌──────────┐ ┌──────────────────┐ │
|
||||
│ │Tokenizer │ DMA→ │ │ │
|
||||
│ └──────────┘ │ Embedding │ │
|
||||
│ ↓ └────────┬─────────┘ │
|
||||
│ ┌──────────┐ ┌────────┴─────────┐ │
|
||||
│ │Control │──Cmd──→ │ Attention L1..N │ │
|
||||
│ │ (plan) │ └────────┬─────────┘ │
|
||||
│ └──────────┘ ┌────────┴─────────┐ │
|
||||
│ ↓ │ FFN L1..N │ │
|
||||
│ ┌──────────┐ └────────┬─────────┘ │
|
||||
│ │Monitor │←──IRQ──│ │ │
|
||||
│ │ (wait) │ ┌────────────┐│
|
||||
│ └──────────┘ ┌───────────────────┐│ Output ││
|
||||
│ │ KV Cache Write │└─────┬──────┘│
|
||||
│ └───────────────────┘ │ │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Timeline:
|
||||
CPU: | Tokenize | Plan | Wait | Monitor | Process Output |
|
||||
NPU: |-------- Embedding + Layers + Output --------|
|
||||
Time: 5ms 20ms (NPU compute) 5ms
|
||||
Total E2E: ~30ms (mostly dominated by NPU)
|
||||
```
|
||||
|
||||
### 3.2 解码阶段的流水线
|
||||
|
||||
```
|
||||
Decode Phase (逐token生成):
|
||||
|
||||
Step i: Step i+1:
|
||||
───────── ─────────
|
||||
CPU: Send Cmd NPU: Execute Layer 1..N
|
||||
Wait ←───────────────→ CPU: Send Cmd
|
||||
NPU: Execute Layer 1..N
|
||||
|
||||
问题: CPU SendCmd 和 NPU Execute 之间有gap
|
||||
原因: NPU完成前CPU需等待
|
||||
|
||||
优化: Double Buffering
|
||||
──────────────────────────────
|
||||
CPU: Send(i) Send(i+1) Send(i+2)
|
||||
NPU: Exec(i) Exec(i+1) Exec(i+2)
|
||||
|
||||
实现:
|
||||
- 两个buffer: buf_A, buf_B
|
||||
- CPU写buf_A时,NPU读buf_A
|
||||
- 完成后swap: CPU写buf_B,NPU读buf_B
|
||||
- 需要RTOS semaphore管理buffer swap
|
||||
```
|
||||
|
||||
## 4. 同步与通信机制
|
||||
|
||||
### 4.1 同步原语
|
||||
|
||||
```c
|
||||
// NPU协同同步原语
|
||||
typedef struct {
|
||||
// 命令同步
|
||||
SemaphoreHandle_t cmd_complete; // 命令完成信号
|
||||
SemaphoreHandle_t data_ready; // 数据就绪信号
|
||||
|
||||
// 双缓冲管理
|
||||
uint8_t *buffers[2]; // 双buffer
|
||||
uint8_t active_buf; // 当前active buffer
|
||||
SemaphoreHandle_t buf_swap; // buffer交换信号
|
||||
|
||||
// 事件通知
|
||||
EventGroupHandle_t events; // 事件组
|
||||
} npu_sync_t;
|
||||
|
||||
// 同步流程
|
||||
void npu_sync_wait(npu_sync_t *sync) {
|
||||
// 等待NPU完成当前命令
|
||||
xSemaphoreTake(sync->cmd_complete, portMAX_DELAY);
|
||||
// 交换buffer
|
||||
xSemaphoreTake(sync->buf_swap, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void npu_sync_signal(npu_sync_t *sync) {
|
||||
// NPU完成中断回调
|
||||
xSemaphoreGiveFromISR(sync->cmd_complete, NULL);
|
||||
xSemaphoreGiveFromISR(sync->buf_swap, NULL);
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 中断处理策略
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Interrupt Hierarchy │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Level 0: Hard IRQ (NPU完成中断) │
|
||||
│ 动作: 提升task优先级, 触发barrier │
|
||||
│ 时间: <10μs │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Level 1: SW IRQ (NPU驱动层) │
|
||||
│ 动作: 释放semaphore, 唤醒task │
|
||||
│ 时间: <50μs │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ Level 2: Soft IRQ (任务调度) │
|
||||
│ 动作: 调度下一个task │
|
||||
│ 时间: <100μs │
|
||||
└─────────────────────────────────────────────┘
|
||||
|
||||
关键设计:
|
||||
- NPU完成中断 → 直接唤醒attention task (不经过软中断)
|
||||
- 使用Interrupt-to-Semaphore模式, 避免context switch开销
|
||||
- 中断处理函数最小化, 尽量defer到task层
|
||||
```
|
||||
|
||||
## 5. 调度策略
|
||||
|
||||
### 5.1 Pipeline并行调度
|
||||
|
||||
```
|
||||
Layer Pipeline (各层在加速器上流水执行):
|
||||
|
||||
Layer: L1 L2 L3 L4
|
||||
[Attn][FFN][Attn][FFN][Attn][FFN][Attn][FFN]
|
||||
CPU: [Plan] [Plan] [Plan] [Plan] [Collect]
|
||||
Time: ↓ ↓ ↓ ↓
|
||||
|
||||
Scheduling:
|
||||
1. CPU先plan Layer 1的Attention
|
||||
2. L1 Attn执行时, CPU plan L2 Attn
|
||||
3. L1 Attn完成 → L1 FFN启动
|
||||
4. CPU plan L3 Attn
|
||||
...
|
||||
|
||||
RTOS实现:
|
||||
- 每个Layer的Attn/FFn是一个task
|
||||
- CPU上跑"planner" task
|
||||
- 加速器上跑"compute" task
|
||||
- 通过barrier同步相邻Layer
|
||||
```
|
||||
|
||||
### 5.2 Cross-device Scheduling (多加速器)
|
||||
|
||||
```
|
||||
Example: SoC with both NPU + GPU
|
||||
|
||||
Request A: Large matrix → NPU (矩阵乘优化)
|
||||
Request B: Conv/Embed → GPU (并行度高)
|
||||
Request C: Small ops → DSP (低功耗)
|
||||
|
||||
调度问题:
|
||||
- 哪个加速器处理哪个请求?
|
||||
- 资源冲突时如何仲裁?
|
||||
- 数据在设备间传输的开销?
|
||||
|
||||
调度策略:
|
||||
1. Capability-based: 根据加速器能力分配
|
||||
2. Load-based: 根据当前负载分配
|
||||
3. Hybrid: capability + load
|
||||
|
||||
RTOS实现:
|
||||
typedef struct {
|
||||
enum accel_type { ACCEL_NPU, ACCEL_GPU, ACCEL_DSP } type;
|
||||
uint32_t utilization; // 当前利用率
|
||||
uint32_t queue_depth; // 排队深度
|
||||
uint64_t avg_latency_us; // 平均延迟
|
||||
SemaphoreHandle_t lock; // 资源锁
|
||||
QueueHandle_t cmd_queue; // 命令队列
|
||||
} accel_resource_t;
|
||||
|
||||
accel_resource_t* select_accelerate(task_t *task) {
|
||||
// 1. Filter by capability
|
||||
if (task->compute_type == MATRIX_MUL) return npu;
|
||||
if (task->compute_type == CONV) return gpu;
|
||||
|
||||
// 2. Pick least loaded
|
||||
return min_utilization(all_accelerators);
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Async Pipeline Scheduling
|
||||
|
||||
```
|
||||
CPU side (RTOS task):
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Task: NPU Dispatcher (priority: HIGH) │
|
||||
│ │
|
||||
│ while (running) { │
|
||||
│ cmd = dequeue_command(); │
|
||||
│ send_to_npu(cmd); │
|
||||
│ wait_for_irq(); │ // 阻塞等待
|
||||
│ if (complete) { │
|
||||
│ process_result(); │
|
||||
│ dispatch_next(); │
|
||||
│ } │
|
||||
│ } │
|
||||
└────────────────────────────────────────────┘
|
||||
|
||||
NPU side (hardware):
|
||||
┌────────────────────────────────────────────┐
|
||||
│ Command Queue (FIFO): │
|
||||
│ ├─ Cmd 1: Attention Layer 1 │
|
||||
│ ├─ Cmd 2: FFN Layer 1 │
|
||||
│ ├─ Cmd 3: Attention Layer 2 │
|
||||
│ └─ ... │
|
||||
│ │
|
||||
│ Execution: Sequential (FIFO) or │
|
||||
│ Out-of-order (with dependencies)│
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 6. 数据传输优化
|
||||
|
||||
### 6.1 DMA策略
|
||||
|
||||
```
|
||||
传输类型 | 策略 | 优化手段
|
||||
---------------------|------------------------|------------------
|
||||
CPU→NPU (weights) | 一次性批量DMA | PCIe burst
|
||||
CPU→NPU (input) | 流水线DMA | 预读
|
||||
NPU→CPU (output) | 完成中断+DMA pull | 零拷贝
|
||||
NPU→NPU (cross) | 共享内存 + cache sync | invalidate+clean
|
||||
|
||||
DMA Descriptor设计:
|
||||
typedef struct {
|
||||
uint32_t src_addr; // 源地址
|
||||
uint32_t dst_addr; // 目的地址
|
||||
uint32_t size; // 传输大小
|
||||
uint32_t flags; // 同步/异步/中断
|
||||
uint32_t completion_irq; // 完成后是否触发中断
|
||||
uint32_t next_desc; // 链式DMA描述符
|
||||
} dma_desc_t;
|
||||
|
||||
// 链式DMA: 多个描述符连成链, 一次性提交
|
||||
// 减少RTOS调用次数, 提高DMA效率
|
||||
void dma_chain_submit(dma_desc_t *head) {
|
||||
// Submit chain to DMA controller
|
||||
// No RTOS calls needed during transfer
|
||||
// Only interrupt on last descriptor
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 零拷贝技术
|
||||
|
||||
```
|
||||
Before:
|
||||
CPU alloc: malloc(input) // 分配
|
||||
memcpy: copy(input) // 拷贝到临时buffer
|
||||
DMA: transfer(temp) // DMA从temp传输
|
||||
Total: 2 copies + 1 DMA
|
||||
|
||||
After (zero-copy):
|
||||
CPU alloc: mmap(shared_mem) // 共享内存
|
||||
Direct: write(shared) // CPU直接写
|
||||
DMA: transfer(shared) // DMA直接从shared传输
|
||||
Total: 0 copies + 1 DMA
|
||||
|
||||
RTOS实现:
|
||||
- 使用mmap或共享内存驱动
|
||||
- CPU和NPU使用同一块物理内存
|
||||
- 通过memory barrier保证一致性
|
||||
- 使用RTOS semaphore管理访问权限
|
||||
```
|
||||
|
||||
## 7. 各平台的加速器协同差异
|
||||
|
||||
### 7.1 MCU级
|
||||
|
||||
```
|
||||
典型: STM32H7 + Cortex-M7 (CPU) + DSP (协处理器)
|
||||
- 无NPU, 纯CPU/DSP矩阵运算
|
||||
- 共享SRAM, 无DMA或简单DMA
|
||||
- 协同简单: CPU调用DSP函数, 等待完成
|
||||
|
||||
关键优化:
|
||||
- DSP的并行化调度
|
||||
- 内存bank切换减少bank冲突
|
||||
- 无共享内存, 需手动memcpy
|
||||
```
|
||||
|
||||
### 7.2 SoC级
|
||||
|
||||
```
|
||||
典型: 骁龙8 Gen + Kryo CPU + Hexagon NPU
|
||||
- NPU驱动封闭, 使用QMI接口通信
|
||||
- 共享内存通过RPMsg (Remote Processor Messaging)
|
||||
- 中断: ARM GIC → Hexagon
|
||||
|
||||
关键挑战:
|
||||
- NPU状态不完全可见
|
||||
- QMI通信有固定开销(~100μs)
|
||||
- 需估算NPU延迟, 不能精确测量
|
||||
|
||||
RTOS策略:
|
||||
- 使用QMI异步API
|
||||
- 通过Event FD等待NPU完成
|
||||
- 双Buffer管理QMI传输
|
||||
```
|
||||
|
||||
### 7.3 Edge盒子
|
||||
|
||||
```
|
||||
典型: Jetson Orin + ARM CPU + NVIDIA GPU
|
||||
- GPU驱动开放, CUDA API可用
|
||||
- 成熟的stream/executor模型
|
||||
- PCIe x16连接
|
||||
|
||||
关键优势:
|
||||
- 可精确控制GPU调度
|
||||
- CUDA Stream可映射为RTOS task
|
||||
- NVLink多GPU调度成熟
|
||||
|
||||
RTOS集成:
|
||||
- CUDA Runtime作为RTOS task的一部分
|
||||
- GPU completion → RTOS event
|
||||
- DMA between CPU↔GPU via PCIe
|
||||
```
|
||||
|
||||
### 7.4 Server级
|
||||
|
||||
```
|
||||
典型: x86 + 多GPU + NVLink
|
||||
- 成熟的vLLM/TGI框架
|
||||
- PCIe/NVLink互联
|
||||
- NUMA拓扑
|
||||
|
||||
RTOS角色:
|
||||
- 管理GPU进程
|
||||
- 处理NVLink中断
|
||||
- 提供实时性保证给GPU inference
|
||||
|
||||
调度:
|
||||
- vLLM already does PagedAttention scheduling
|
||||
- RTOS主要保障中断响应
|
||||
```
|
||||
|
||||
## 8. 关键设计决策
|
||||
|
||||
| 决策点 | 选项 | 推荐 | 理由 |
|
||||
|-------|------|-----|------|
|
||||
| 同步模式 | Sync / Async / Event | **Async + Event** | 最大化并行度 |
|
||||
| 缓冲策略 | Single / Double / Triple | **Triple** | 最大化流水线效率 |
|
||||
| 数据传输 | Copy / DMA / Shared | **DMA + Shared** | 零拷贝+低CPU占用 |
|
||||
| 加速决策 | Static / Dynamic | **Dynamic** | 根据负载自动选择 |
|
||||
| 中断模式 | Polling / Interrupt / Event | **Interrupt** | 实时性最好 |
|
||||
| 错误处理 | Retry / Skip / Report | **Retry + Report** | 保证正确性 |
|
||||
|
||||
## 9. 开放研究问题
|
||||
|
||||
1. **Black-box NPU Scheduling**: 加速状态不可知时的调度策略?
|
||||
2. **Cross-accelerator Load Balancing**: 多加速器间的动态负载均衡?
|
||||
3. **Accelerator Fault Recovery**: 加速器故障时的降级调度?
|
||||
4. **Predictive Pipeline**: 预测NPU延迟, 优化pipeline stall?
|
||||
5. **Heterogeneous Memory**: CPU/NPU共享内存的一致性管理?
|
||||
|
||||
---
|
||||
|
||||
*最后更新: 2026-09-17*
|
||||
Reference in New Issue
Block a user