3、多核调度概念:掌握多核NPU调度的基本概念、并发模型与核心分配的核心术语

在RK3576、RK3588等新一代瑞芯微平台中,NPU(神经网络处理单元)已不再是单一计算核心的简单加速器,而是演变为包含多个独立计算核心、共享存储与专用调度引擎的复杂计算子系统。多核NPU调度的本质,是在有限硬件资源(核心数、带宽、内存)约束下,将多个深度学习推理任务(或单个大模型的分层计算)高效映射到多个NPU核心上执行的过程。理解这一概念,需要首先厘清“并发模型”与“核心分配”两个维度的核心术语,并建立从硬件拓扑到软件调度策略的完整认知框架。

多核NPU调度概念框架 硬件资源层 Core 0 Core 1 Core 2 Core 3 共享SRAM / 带宽 / 中断控制器 调度策略层 同步调度 (SPMD) 异步调度 (MPMD) 负载均衡 / 优先级 / 抢占 任务与核心分配 任务A → Core 0/1 任务B → Core 2 核心亲和性 / 绑核 / 时间片 关键性能指标 • 吞吐量 (Throughput):单位时间完成推理任务数 • 时延 (Latency):单任务从提交到完成的时间 • 核心利用率 (Core Utilization):各NPU核心实际计算时间占比 • 调度开销 (Scheduling Overhead):调度器自身消耗的CPU/时间 • 公平性 (Fairness):多任务间资源获取的均衡程度 • 可扩展性 (Scalability):增加核心后性能提升比例

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),需设置最小执行时间保证。