Files
rtos_llm_opt/项目框架1-基于RTOS的五类场景AI实时性研究/10-研究框架/03-加速器协同调度.md
T

458 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 方向3: 加速器协同调度 (CPU + NPU/GPU)
## 1. 问题陈述
任务关键系统中的人工智能目标负载往往依赖专用加速器(NPU/GPU/DSP)与 CPU 协同完成计算。RTOS 需要协调 CPU 与加速器协同工作。核心问题:
1. **速度不匹配**: CPU和加速器的速度比通常是1:5~1:10,容易产生stall
2. **状态不可见**: NPU驱动通常封闭,无法精确感知NPU状态
3. **数据传输开销**: CPU↔NPU的数据传输是瓶颈
4. **同步开销**: barrier/semaphore的实时性分析复杂
### 1.1 本方向在总课题中的角色
本方向聚焦:
- 如何让 RTOS 对人工智能目标负载的设备计算阶段建立可管理的节拍;
- 如何避免 CPU、加速器、DMA 和中断之间的协同开销侵蚀关键保障负载边界;
- 如何把异构设备协同从黑盒调用,转化为可分析、可限流、可恢复的系统机制。
因此,这一方向服务的是总课题中的“设备协同与异构执行可预测性”主线。
### 1.2 与验证矩阵的对应关系
加速器协同在 `T5~T1` 中的实现方式差异很大,因此需要按部署形态看重点:
| 部署形态 | 加速器协同侧重点 |
|---|---|
| `T5` 控制端 | 无加速器或轻量 DSP/NPU 下的简化协同 |
| `T4` 终端设备 | SoC 内 CPU 与片上 NPU 的同步与拷贝开销 |
| `T3` 边缘节点 | 多核 CPU 与外设/NPU/GPU 的流水线协同 |
| `T2` 单机工作站 | CPU 与独立 GPU 的队列、DMA 与中断协同 |
| `T1` 服务器/集群 | 多 GPU、多 NUMA 域与多进程协同执行 |
## 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. 本方向的验证关注点
为了让本方向与总课题的双目标评价框架对齐,加速器协同机制至少要回答下面三个问题:
1. 设备协同是否降低了人工智能目标负载的等待时间、传输开销和端到端抖动;
2. DMA、中断和共享内存竞争是否会冲击关键保障负载的响应时间边界;
3. 当加速器状态不可见、延迟波动或发生故障时,系统是否仍具备准入、限流和恢复能力。
## 9. 关键设计决策
| 决策点 | 选项 | 推荐 | 理由 |
|-------|------|-----|------|
| 同步模式 | 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** | 保证正确性 |
## 10. 开放研究问题
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*