16、多路Camera调度与QoS:CPU/GPU/DSP资源分配、优先级管理、带宽保障

各位做车载Camera的朋友,咱们今天聊一个很实际的问题——多路Camera的调度。

你想想看,现在的智能汽车,少说也有4-6个摄像头。环视、DMS、OMS、ADAS感知……这些摄像头同时工作,CPU、GPU、DSP、ISP全都在抢资源。怎么保证每个摄像头都能拿到它需要的算力和带宽?这就是QoS要解决的问题。

我个人习惯把这个问题拆成三个层面来看:资源分配优先级管理带宽保障。咱们一个一个说。

16.1 资源分配:谁该拿多少算力?

先说CPU。多路Camera进来,每一路都要做预处理、格式转换、算法推理。CPU资源是有限的,你不能让一路Camera把CPU吃满,其他路饿死。

我在项目中遇到过这样一个坑:某款车型的环视系统,4路摄像头同时工作,结果有一路因为CPU被抢走,帧率从30fps掉到了12fps。后来一查,是某个算法模块没有做CPU亲和性绑定,导致它被调度到了同一个核心上。

解决方案其实不复杂:

  • CPU亲和性绑定:把关键线程绑定到特定核心上,避免被其他线程干扰。
  • CPU使用率上限:给每个Camera pipeline设置CPU使用率上限,比如不超过30%。
  • GPU/DSP负载均衡:能丢给DSP做的,就别让CPU做。比如图像预处理、色彩校正这些,DSP效率高得多。

关键点:资源分配不是简单的“平均分”,而是“按需分”。比如ADAS摄像头需要高帧率、低延迟,那它就应该拿到更多的CPU和GPU资源。而环视摄像头对延迟要求没那么高,可以适当降低优先级。

16.2 优先级管理:谁先谁后?

优先级管理说白了就是:当资源不够时,谁先上,谁等着。

我记得有一次调试DMS摄像头,发现它总是丢帧。后来一查,是因为它和ADAS摄像头共享同一个ISP pipeline,而ADAS的优先级更高,导致DMS的帧被丢弃了。

这里我建议的做法是:

  1. 定义Camera优先级等级:比如ADAS > DMS > 环视 > 娱乐摄像头。
  2. 使用实时线程:高优先级的Camera pipeline使用SCHED_FIFO或SCHED_RR调度策略。
  3. 优先级继承:当低优先级线程持有高优先级线程需要的锁时,临时提升它的优先级,避免优先级反转。

小技巧:我曾经在项目中用了一个“优先级门限”机制——当CPU使用率超过80%时,自动降低非关键Camera的优先级。这样既保证了关键功能,又不会让系统崩溃。

16.3 带宽保障:数据通路不能堵

带宽问题,说白了就是数据能不能及时从摄像头传到处理器。这里涉及三个环节:

  • MIPI CSI带宽:每个摄像头占用的MIPI lane数量和速率。
  • 内存带宽:多路Camera同时写入DDR,会不会造成带宽瓶颈?
  • ISP带宽:ISP的处理能力能不能跟上所有Camera的帧率?

我遇到过最头疼的问题,就是内存带宽被打满。4路1080p@30fps的Camera同时写入DDR,再加上GPU在做渲染,结果内存带宽直接爆了。系统卡顿,Camera掉帧,甚至出现画面撕裂。

解决方案:

  • 使用ION内存分配器:为Camera分配专用的物理连续内存,避免碎片化。
  • 设置内存带宽上限:通过DMA-BUF的QoS接口,限制每路Camera的内存带宽使用量。
  • 使用硬件压缩:比如NV12转NV21时,用硬件压缩减少带宽占用。

注意:带宽问题不是简单的“加带宽”就能解决的。有时候是总线仲裁策略的问题,有时候是内存控制器配置的问题。我曾经花了两周时间,最后发现是DDR的page policy配置不对,导致多路写入时冲突严重。

16.4 整体调度框架

说了这么多,咱们来看一个实际的调度框架图。这个图是我在某个项目中用过的,效果还不错。

多路Camera QoS调度框架 Camera 1 (ADAS) Camera 2 (DMS) Camera 3 (环视) Camera N QoS调度器 CPU亲和性绑定 | 优先级管理 | 带宽限制 | 资源预留 CPU核心 GPU/DSP ISP + 内存带宽 监控与反馈 帧率统计 | CPU/GPU使用率 | 带宽占用 | 延迟测量 动态调整QoS参数

这个框架的核心思路是:先分配,再调度,最后监控反馈。每一路Camera进来,QoS调度器根据它的优先级和资源需求,分配CPU核心、GPU/DSP时间片、内存带宽。然后通过监控模块实时反馈,动态调整参数。

16.5 代码示例:QoS配置

最后,给一段实际代码。这是我在Android HAL层配置Camera QoS的片段:

// Camera QoS配置结构体
typedef struct {
    int32_t camera_id;
    int32_t priority;          // 0-255, 越高越优先
    int32_t cpu_affinity;      // CPU亲和性掩码
    int32_t cpu_usage_max;     // CPU使用率上限(%)
    int32_t gpu_time_slice;    // GPU时间片(ms)
    int32_t mem_bandwidth_max; // 内存带宽上限(MB/s)
    int32_t mipi_lane_count;   // MIPI lane数量
    int32_t mipi_freq;         // MIPI频率(MHz)
} camera_qos_config_t;

// 配置ADAS摄像头
camera_qos_config_t adas_qos = {
    .camera_id = 0,
    .priority = 200,
    .cpu_affinity = 0x0F,      // 绑定到核心0-3
    .cpu_usage_max = 40,
    .gpu_time_slice = 10,
    .mem_bandwidth_max = 800,
    .mipi_lane_count = 4,
    .mipi_freq = 1200
};

// 配置环视摄像头
camera_qos_config_t surround_qos = {
    .camera_id = 1,
    .priority = 100,
    .cpu_affinity = 0xF0,      // 绑定到核心4-7
    .cpu_usage_max = 20,
    .gpu_time_slice = 5,
    .mem_bandwidth_max = 400,
    .mipi_lane_count = 2,
    .mipi_freq = 800
};

// 应用QoS配置
int ret = camera_qos_apply(&adas_qos);
if (ret != 0) {
    // 处理失败
}

避坑指南:我曾经在配置CPU亲和性时,把ADAS和DMS绑定到了同一个核心上。结果两个高优先级线程互相抢资源,导致系统响应变慢。后来我改成每个关键Camera独占一个核心,问题就解决了。

嗯,关于多路Camera调度与QoS,今天就聊这么多。核心就三句话:资源要按需分配,优先级要明确,带宽要保障。你想想看,如果这三条都做到了,多路Camera系统基本上就不会出大问题。


公众号:蓝海资料掘金营,微信deep3321