3、多核调度概念:掌握多核NPU调度的基本概念、并发模型与核心分配的核心术语
在RK3576、RK3588等新一代瑞芯微平台中,NPU(神经网络处理单元)已不再是单一计算核心的简单加速器,而是演变为包含多个独立计算核心、共享存储与专用调度引擎的复杂计算子系统。多核NPU调度的本质,是在有限硬件资源(核心数、带宽、内存)约束下,将多个深度学习推理任务(或单个大模型的分层计算)高效映射到多个NPU核心上执行的过程。理解这一概念,需要首先厘清“并发模型”与“核心分配”两个维度的核心术语,并建立从硬件拓扑到软件调度策略的完整认知框架。
3.1 多核NPU的硬件拓扑与并发模型
RK3588的NPU集成了三个独立计算核心(Core 0/1/2),每个核心拥有独立的MAC阵列、激活单元和池化单元,但共享L2缓存、DDR带宽以及中断控制器。这种“多核心、共享存储”的架构决定了并发模型必须考虑数据竞争和带宽争用。从软件视角看,多核NPU支持两种基本并发模型:数据并行(Data Parallelism)与模型并行(Model Parallelism)。数据并行将同一模型复制到多个核心,每个核心处理不同的输入批次(batch),适用于高吞吐量场景;模型并行则将一个大模型按层或按分支拆分到不同核心,核心间通过流水线方式协作,适用于单个模型过大无法放入单核心内存的场景。
核心术语对照表
| 术语 | 英文缩写 | 定义 | 典型应用场景 |
|---|---|---|---|
| 核心绑定 | Core Affinity | 将特定任务固定到指定NPU核心,避免迁移开销 | 实时性要求高的检测任务 |
| 时间片轮转 | Time Slicing | 多个任务按时间片交替占用同一核心 | 多路视频流分析 |
| 任务队列 | Task Queue | 调度器维护的待执行任务列表,支持优先级排序 | 混合推理负载 |
| 同步屏障 | Barrier | 多核心任务必须等待所有核心到达后才能继续 | 模型并行中的层间同步 |
| 工作窃取 | Work Stealing | 空闲核心主动从繁忙核心队列中取任务 | 动态负载均衡 |
| 张量拆分 | Tensor Splitting | 将输入张量按通道或空间维度切分到多核心 | 大分辨率图像分类 |
在RKNN Toolkit中,调度模型通过rknn_init时的core_mask参数指定核心使用策略。例如,RKNN_NPU_CORE_0_1_2表示使用全部三个核心,而RKNN_NPU_CORE_0仅使用单核。并发模型的选择直接影响调度器的行为:数据并行模式下,调度器倾向于将同一模型的多个实例分散到不同核心;模型并行模式下,调度器则需维护核心间的依赖关系,确保前序核心的输出作为后续核心的输入。
3.2 核心分配策略与调度算法
核心分配策略解决“哪个任务放到哪个核心”的问题。RKNN调度器支持静态分配与动态调度两种模式。静态分配在模型加载时确定核心映射,适合负载固定的场景;动态调度则根据运行时核心利用率、任务优先级和队列长度实时调整。核心分配的核心术语包括:负载均衡因子(Load Balance Factor)、核心亲和性掩码(Affinity Mask)、优先级反转(Priority Inversion)以及调度延迟(Scheduling Latency)。
实际操作中,开发者通过rknn_set_core_mask接口动态调整核心分配。例如,当检测到Core 0利用率超过90%而Core 1空闲时,可将新到达的任务绑定到Core 1。调度算法方面,RKNN底层采用基于优先级的抢占式调度,同时支持加权公平队列(WFQ)来保证多路任务间的带宽公平性。对于实时性要求高的任务(如自动驾驶目标检测),建议使用RKNN_NPU_CORE_0独占核心,避免与其他任务争用。
// 核心分配示例代码
rknn_context ctx;
rknn_init(&ctx, model_path, 0, RKNN_NPU_CORE_0_1, NULL);
// 运行时动态调整:将后续推理绑定到Core 2
rknn_set_core_mask(ctx, RKNN_NPU_CORE_2);
// 查询当前核心利用率
rknn_query(ctx, RKNN_QUERY_NPU_UTILIZATION, &util, &size);
3.3 案例拆解:多路视频流分析中的核心分配优化
某安防场景需要在RK3588平台上同时处理8路1080p视频流,每路视频流运行YOLOv5s目标检测模型。初始方案将所有任务平均分配到3个NPU核心,但实测发现Core 0利用率达95%,Core 1为60%,Core 2仅为35%,整体吞吐量仅达到预期值的70%。分析日志发现,视频流解码中断集中在Core 0关联的CPU核心上,导致NPU Core 0频繁等待输入数据。
优化过程分为三步:首先,通过rknn_query获取各核心的实时利用率,确认负载不均;其次,将8路视频流按场景复杂度分组——4路固定摄像头(低负载)绑定到Core 2,3路动态摄像头(中负载)绑定到Core 1,1路人流密集区域(高负载)独占Core 0;最后,在应用层使用pthread_setaffinity_np将视频解码线程绑定到与NPU核心对应的CPU核心上,减少跨核心通信开销。调整后,核心利用率分别稳定在88%、82%、79%,整体吞吐量提升至理论值的92%,时延从45ms降至32ms。
经验提醒:核心分配并非越多越好。当模型较小时(如MobileNet),多核心并行带来的通信开销可能超过计算收益。建议对模型耗时进行单核/双核/三核基准测试,找到性能拐点。此外,共享SRAM容量有限,多核心同时访问大张量时容易产生带宽瓶颈,此时应优先考虑数据复用而非核心数量。
3.4 常见误区与总结复盘
误区一:将“多核”等同于“线性加速”。实际加速比受Amdahl定律约束,串行部分(如预处理、后处理)无法并行化。RK3588三核NPU对YOLOv5s的实测加速比约为2.3倍,而非3倍。
误区二:忽略调度器自身的CPU开销。频繁调用rknn_set_core_mask或创建过多任务队列会消耗CPU资源,在CPU负载已高的场景下反而降低整体性能。建议将核心分配策略设置为“加载时确定,运行时微调”,避免每帧都调整。
误区三:混淆“并发”与“并行”。并发是逻辑上的同时处理(任务交替执行),并行是物理上的同时执行(多核心同时计算)。RKNN调度器支持真正的并行,但若任务间存在数据依赖,则只能并发执行。
误区四:忽视中断与DMA通道的竞争。多核心同时发起DMA传输时,共享总线可能成为瓶颈。通过rknn_set_mem_pool为不同核心分配独立内存区域,可减少总线争用。
风险提示:在模型并行模式下,若某个核心的计算量显著大于其他核心,会导致其他核心空闲等待,形成“木桶效应”。务必使用性能分析工具(如RKNN Profiler)定位热点层,必要时调整模型切分点。另外,动态调度策略在极端负载下可能引发任务饿死(Starvation),需设置最小执行时间保证。