3、多模型调度核心概念:任务、流水线、并行度、资源竞争、调度策略等术语解析
在BM1684平台上进行多模型部署时,我们面对的不是单个模型的独立运行,而是一组模型在有限算力、内存和带宽资源下的协同工作。多模型调度的本质,是在时间维度和空间维度上对芯片资源进行精细切分与复用。要理解这一过程,首先需要建立一套统一的术语体系——任务(Task)、流水线(Pipeline)、并行度(Parallelism)、资源竞争(Resource Contention)和调度策略(Scheduling Policy)构成了这套体系的核心骨架。这些概念并非孤立存在,它们相互关联、彼此制约,共同决定了多模型系统的吞吐量、延迟和资源利用率。本节将逐一拆解这些术语的内涵,并结合BM1684的硬件特性(如TPU内核、DDR带宽、SDMA通道)说明它们在实际工程中的具体表现。
上图展示了多模型调度中五个核心概念之间的逻辑关系。调度策略处于中心位置,它接收任务的资源需求描述,结合并行度的设定,在流水线的各个阶段中分配资源,同时监控资源竞争状况并动态调整分配方案。这张图是理解后续所有调度机制的总纲——在实际工程中,我们通常先定义任务模型,再设计流水线结构,然后确定并行度参数,最后通过调度策略来协调资源竞争。下面逐一展开每个概念的详细内涵。
3.1 任务(Task):调度的最小执行单元
核心原理:在BM1684多模型调度语境下,任务(Task)不是指一个模型文件,而是指一次具体的执行请求——它包含了模型实例、输入数据、优先级、截止时间以及资源需求描述。一个检测模型可以被实例化为多个任务,每个任务处理不同的视频帧或图像批次。任务具有生命周期:创建(Create)、就绪(Ready)、运行(Running)、阻塞(Blocked)、完成(Completed)和销毁(Destroy)。调度器只关心处于就绪状态的任务,并根据某种策略从中选择下一个运行的任务。
任务描述通常包含以下关键字段:
| 字段 | 类型 | 说明 | 示例值 |
|---|---|---|---|
| task_id | uint32 | 全局唯一标识 | 0x3A2F |
| model_id | uint32 | 指向已加载的模型句柄 | 2(检测模型) |
| input_buf | void* | 输入数据的内存地址(DDR或SRAM) | 0x8000_0000 |
| priority | uint8 | 0-255,数值越大优先级越高 | 200 |
| deadline | uint64 | 期望完成的时间戳(us) | 1,725,600,000 |
| tpu_cycles | uint32 | 预估TPU计算周期数 | 1,200,000 |
| ddr_bytes | uint32 | 预估DDR读写字节数 | 8,388,608 |
判断方法:在BM1684的TPU-Kernel编程框架中,任务通常通过bm_tpu_kernel_launch()接口提交。判断一个任务是否适合独立调度,需要看它是否满足以下条件:①输入数据已准备就绪;②所需的模型权重已加载到DDR;③目标TPU内核空闲或可抢占;④任务的资源需求(TPU周期、DDR带宽)可被当前调度器满足。如果任务依赖其他任务的输出(如检测结果送入分类模型),则属于流水线依赖任务,需要特殊处理。
3.2 流水线(Pipeline):多模型协作的结构化组织
核心原理:流水线是将一个完整的推理业务拆分为多个顺序或并行的阶段(Stage),每个阶段由一个或多个模型实例负责。在BM1684上,典型的视觉处理流水线为:视频解码 → 目标检测 → 目标分类 → 目标跟踪 → 结果编码。每个阶段可以运行在不同的TPU内核上,也可以在同一内核上分时复用。流水线的核心价值在于:通过阶段间的重叠执行(Overlap),隐藏单个阶段的延迟,从而提升整体吞吐量。
流水线设计的关键参数包括:
- 阶段数(K):流水线的深度,阶段越多,并行潜力越大,但同步开销也越高。
- 阶段处理时间(t_i):每个阶段的平均执行时间,流水线的吞吐量受最慢阶段(瓶颈阶段)限制。
- 缓冲深度(B):相邻阶段之间的队列缓冲容量,决定了流水线能够容忍的抖动幅度。
- 数据依赖类型:顺序依赖(前一阶段输出是后一阶段输入)或条件依赖(后一阶段仅处理特定输出)。
操作流程:在BM1684上搭建多模型流水线,通常遵循以下步骤:
- 阶段划分:根据业务逻辑将推理过程拆分为若干独立阶段,每个阶段对应一个模型或一个预处理/后处理算子。
- 资源分配:为每个阶段分配TPU内核、DDR缓冲区和SDMA通道。BM1684拥有2个TPU内核,可以将检测模型放在内核0,分类和跟踪模型共享内核1。
- 缓冲设计:使用双缓冲(Double Buffering)或环形缓冲(Ring Buffer)连接相邻阶段。双缓冲允许一个阶段在写入缓冲B时,下一阶段同时读取缓冲A。
- 同步机制:使用信号量或事件标志实现阶段间的同步。BM1684的TPU-Kernel提供了
bm_sem_wait()和bm_sem_post()接口。 - 背压控制:当下游阶段处理速度慢于上游时,需要背压机制防止缓冲溢出。通常通过限制缓冲深度或使用丢弃策略实现。
3.3 并行度(Parallelism):空间维度的资源复用
核心原理:并行度描述的是在同一时刻有多少个任务在同时执行。在BM1684上,并行度可以从四个层次理解:
| 并行类型 | 硬件基础 | 典型粒度 | 适用场景 |
|---|---|---|---|
| 模型并行 | 2个TPU内核 | 一个模型拆分为两部分,分别在不同内核运行 | 超大模型(如YOLOv5x)单内核放不下 |
| 数据并行 | 同一模型多实例 | 不同输入批次同时推理 | 多路视频流检测 |
| 流水线并行 | 阶段间重叠 | 不同阶段处理不同数据 | 检测+分类+跟踪串联 |
| 任务并行 | TPU内核+SDMA | 不同模型同时执行 | 检测与跟踪同时进行 |
判断方法:确定并行度时,需要先计算理论峰值并行度。BM1684的INT8算力为17.6 TOPS,FP32为2.2 TFLOPS。假设检测模型需要5 TOPS,分类模型需要1 TOPS,跟踪模型需要2 TOPS,那么理论上可以同时运行检测+分类+跟踪(共8 TOPS < 17.6 TOPS)。但实际还要考虑DDR带宽限制——BM1684的DDR4带宽为51.2GB/s,如果三个模型的总DDR访问量超过该值,则无法达到计算并行度。
案例拆解:假设一个智慧安防场景需要同时处理8路1080p@30fps视频流,每路视频流需要执行检测(YOLOv5s)、分类(ResNet18)和跟踪(DeepSORT)。
- 初始方案:每路视频流独立运行一个完整流水线,即8个检测模型实例+8个分类实例+8个跟踪实例。这需要24个模型实例,远超BM1684的承载能力。
- 优化方案:将检测模型合并为2个实例(每个实例处理4路视频流,通过batch=4实现数据并行),分类模型合并为2个实例,跟踪模型合并为2个实例。总实例数降为6个,每个TPU内核运行3个实例。
- 并行度计算:检测模型batch=4时,TPU利用率约85%;分类模型batch=4时,利用率约60%;跟踪模型batch=4时,利用率约40%。总TPU负载约185%,超过100%,因此需要将跟踪模型降为batch=2,或调整调度策略使跟踪模型在检测/分类的空闲间隙运行。
3.4 资源竞争(Resource Contention):性能下降的根源
核心原理:资源竞争发生在多个任务同时请求同一类有限资源时。BM1684上的资源竞争主要出现在三个层面:
- TPU算力竞争:两个任务同时需要TPU内核执行矩阵运算。BM1684的2个TPU内核各自独立,但共享指令发射单元和部分缓存。
- DDR带宽竞争:所有模型权重、输入输出数据都存储在DDR中。当多个任务同时进行大量DMA读写时,带宽成为瓶颈。实测中,当DDR带宽利用率超过80%时,有效带宽会因刷新和仲裁开销而下降。
- SDMA通道竞争:BM1684有多个SDMA通道用于数据搬运,但通道数量有限(通常8-16个)。当任务数量超过通道数时,DMA请求需要排队。
判断方法:识别资源竞争的关键是监控性能计数器。BM1684提供了硬件性能计数器,可以读取以下指标:
// 伪代码:读取TPU利用率
uint32_t tpu_util = bm_read_counter(BM_TPU_UTILIZATION);
// 读取DDR带宽利用率
uint32_t ddr_bw_util = bm_read_counter(BM_DDR_BANDWIDTH_UTIL);
// 读取SDMA队列深度
uint32_t sdma_queue_depth = bm_read_counter(BM_SDMA_QUEUE_DEPTH);
// 判断竞争程度
if (tpu_util > 90 && ddr_bw_util > 70) {
// TPU和DDR同时高负载,存在严重竞争
// 建议降低并行度或调整任务优先级
}
案例拆解:在某项目中,检测模型和分类模型同时运行时,检测延迟从8ms增加到15ms,分类延迟从3ms增加到7ms。通过性能计数器发现:
- TPU内核0利用率:95%(检测),内核1利用率:88%(分类)
- DDR带宽利用率:82%(接近饱和)
- SDMA队列深度:平均6.3(峰值12)
分析判断:DDR带宽是主要瓶颈。检测模型每次推理需要读取约50MB权重和特征图,分类模型需要约20MB。两者同时运行时,DDR带宽需求为(50+20)MB/8ms ≈ 8.75GB/s,加上其他开销,实际需求约12GB/s,接近51.2GB/s的25%——但实际利用率却达到82%,说明存在大量非连续访问和缓存未命中。
优化操作:①将检测模型的权重从DDR加载到SRAM(BM1684有2MB SRAM),减少DDR访问;②调整分类模型的batch大小从8降到4,减少瞬时带宽需求;③为检测任务设置更高优先级,确保关键路径不受影响。优化后,检测延迟恢复到9ms,分类延迟为5ms,整体吞吐量提升22%。
3.5 调度策略(Scheduling Policy):资源分配的核心决策
核心原理:调度策略决定了在多个就绪任务中,哪个任务获得资源、获得多少资源、运行多长时间。BM1684多模型调度中常用的策略包括:
| 策略名称 | 核心思想 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 先来先服务(FCFS) | 按提交顺序执行 | 实现简单,公平 | 短任务被长任务阻塞 | 任务长度相近 |
| 固定优先级(FP) | 高优先级任务先执行 | 保证关键任务延迟 | 低优先级任务可能饿死 | 检测>分类>跟踪 |
| 时间片轮转(RR) | 每个任务运行固定时间片 | 公平,响应快 | 上下文切换开销大 | 多路视频流均衡处理 |
| 最早截止时间优先(EDF) | 截止时间最近的任务先执行 | 满足实时性要求 | 需要精确的截止时间估计 | 实时跟踪场景 |
| 资源感知调度(RAS) | 根据资源需求匹配 | 最大化资源利用率 | 计算复杂度高 | 混合负载场景 |
操作流程:在BM1684上实现调度策略,通常采用两级调度架构:
- 全局调度器:运行在ARM CPU上(BM1684集成8核ARM A53),负责跨模型的任务分配。它维护一个全局任务队列,根据策略选择下一个要执行的任务,并分配TPU内核和DDR带宽配额。
- 局部调度器:每个TPU内核内部有一个简单的硬件调度器,负责处理已分配到该内核的任务队列。局部调度器通常采用FIFO或简单优先级策略。
案例拆解:一个智能交通系统需要同时运行车辆检测(高优先级,实时性要求高)、车牌识别(中优先级)和交通流量统计(低优先级,离线分析)。
- 初始策略:使用固定优先级,检测任务优先级200,车牌识别150,流量统计100。结果:检测延迟稳定在5ms,但流量统计任务几乎得不到执行,数据积压严重。
- 改进策略:采用优先级+时间片混合策略。检测任务优先级200,但每个时间片最长占用2ms;车牌识别优先级150,时间片3ms;流量统计优先级100,时间片5ms。同时,当检测任务连续3个周期都未超过截止时间时,动态降低其优先级10%,将释放的资源让给流量统计。
- 结果对比:检测延迟从5ms增加到6ms(仍在容忍范围内),车牌识别延迟从12ms降到8ms,流量统计的积压数据从10万帧降到2万帧。整体系统吞吐量提升35%。
3.6 常见误区与总结复盘
误区一:认为并行度越高越好。实际上,当并行度超过资源承载能力时,任务排队和上下文切换开销会抵消并行收益。BM1684上,2个TPU内核最多支持2个计算密集型任务同时运行,但如果有DDR带宽瓶颈,实际并行度可能只有1.5。
误区二:忽略任务间的隐式依赖。即使两个模型在逻辑上独立,它们可能共享同一个输入缓冲区或模型权重。如果调度器没有感知这种依赖,可能导致数据竞争或权重被意外覆盖。
误区三:将调度策略与模型加载混为一谈。模型加载(将权重从文件系统读入DDR)是IO密集型操作,不应占用TPU资源。正确的做法是在系统初始化阶段预加载所有模型,运行时只调度推理任务。
误区四:不监控资源竞争就盲目调参。没有性能计数器数据的调度优化是盲目的。建议在开发板上运行bm_profile工具,获取详细的资源使用时间线,再针对瓶颈进行优化。
总结复盘:本节解析的五个核心概念构成了多模型调度的完整知识框架。任务定义了“调什么”,流水线定义了“按什么顺序调”,并行度定义了“同时调多少”,资源竞争定义了“为什么调不快”,调度策略定义了“具体怎么调”。在BM1684的实际开发中,建议按照以下路径落地:①先明确业务需求,定义任务模型和优先级;②设计流水线结构,确定阶段划分和缓冲策略;③根据硬件资源计算理论并行度;④通过性能计数器识别资源竞争点;⑤选择合适的调度策略并持续调优。这五个步骤环环相扣,每一步的决策都会影响最终的系统性能。