十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

034、影像虚拟化资源管理——高通骁龙平台的虚拟机间ISP共享与QoS保障机制

034、影像虚拟化资源管理——高通骁龙平台的虚拟机间ISP共享与QoS保障机制 034、影像虚拟化资源管理——高通骁龙平台的虚拟机间ISP共享与QoS保障机制去年年底在帮一家车厂做8155平台的智能座舱方案时碰到一个特别诡异的案子。客户报障说倒车影像偶尔会卡顿而且不是那种帧率掉到20fps的卡顿是那种画面突然停顿一下、然后跳变的感觉像极了丢帧。我们一开始怀疑是摄像头驱动的问题查了三天把CSI2的时序、MIPI的lane分配、甚至线束的屏蔽层都翻了个底朝天毫无头绪。后来把日志拉出来发现一个关键线索——卡顿发生的时刻正好是仪表盘上的导航地图在做3D渲染切换的瞬间。这就对上了问题出在虚拟化层而不是物理链路。这代8155的ISP是支持硬件虚拟化的也就是说一个物理ISP可以被切成多个虚拟ISP实例分别给仪表系统QNX和座舱系统Android用。但问题在于高通默认的虚拟化方案里ISP的带宽和算力分配是静态的按比例切好就固定了。我们当时给仪表侧分了60%的ISP资源给座舱侧分了40%。结果导航3D渲染一跑起来座舱侧的GPU和ISP争抢DDR带宽ISP的吞吐量瞬间掉到阈值以下虚拟ISP实例就开始丢帧。而仪表侧虽然只用了60%的资源但因为它的虚拟ISP实例优先级高反而没受影响。这事的本质是静态分区在动态负载面前就是纸糊的墙。高通在骁龙平台上解决这个问题的核心机制叫“ISP QoS Token Bucket”说白了就是一个令牌桶算法但实现细节相当讲究。每个虚拟ISP实例都有一个独立的令牌桶桶的容量和填充速率由系统侧的TZTrustZone固件在启动时配置。关键点在于这个配置不是死的它允许运行时的动态调整但调整的入口不在Linux内核里而在一个叫“Camera Resource Manager”的微核服务里。这个微核跑在TZ的信任域里普通内核驱动只能通过SMC调用去请求调整不能直接改寄存器。这里踩过一个坑——我们一开始想当然地在Android内核里直接写ISP的QoS寄存器结果一写就触发安全异常整个相机服务直接crash。后来才明白高通的虚拟化安全模型里ISP的QoS寄存器是TZ独占的非安全世界只能通过请求-授权的方式间接控制。实际调优的时候光理解令牌桶还不够得搞清楚令牌桶的“突发容量”和“持续速率”分别对应什么。持续速率决定了虚拟ISP实例的保底带宽突发容量决定了它能瞬间借用的额外带宽。我们当时把仪表侧的突发容量调得很大想着反正它平时用不满不如让座舱侧在导航渲染时能借点带宽。结果发现令牌桶的借用机制有个隐藏约束——它只能借用同属一个“QoS域”的空闲令牌而8155上仪表和座舱默认分属不同的QoS域。跨域借用需要额外配置一个“共享池”这个共享池的大小在PILPeripheral Image Loader加载ISP固件时就得定好运行期改不了。所以正确的做法是在启动阶段就把共享池预留出来而不是等出问题了再想办法。代码层面高通提供了一个叫cam_sync_qos_request的接口但别指望它开箱即用。这个接口的入参是一个结构体里面有个qos_priority字段取值范围是0到255。我们一开始按直觉把座舱侧的优先级设成200仪表侧设成50想着高优先级肯定先保障。结果完全反了——高通的QoS语义里数值越小优先级越高0是最高255是最低。这个反直觉的设计坑了不少人我们后来在代码注释里专门写了警示。另外cam_sync_qos_request是异步的它只是把请求挂到队列里真正的生效要等TZ侧的回调确认。如果你在请求后立刻去读ISP的带宽统计寄存器读到的还是旧值必须等一个CAM_SYNC_QOS_ACK事件。这里有个调试技巧可以在TZ侧开一个trace点用atrace抓SMC调用的时间戳能精确看到请求到确认的延迟正常应该在微秒级如果超过100微秒基本可以断定TZ侧有别的安全服务在抢占CPU。再往深一层说虚拟化ISP共享的瓶颈往往不在ISP本身而在它下游的“图像处理管线”的DDR带宽。高通把ISP的输出直接写到DDR的特定区域然后由各自的虚拟机去读取。如果两个虚拟机的DDR访问模式是“交错突发”的比如仪表侧每写一行就切到座舱侧那DDR的bank冲突会非常严重实际带宽可能只有理论值的60%。解决这个问题要靠“DDR QoS Port”的配置在8155上叫DDR_QOS_PORT_ISP0和DDR_QOS_PORT_ISP1这两个端口可以设置不同的仲裁权重。我们最后是把仪表侧的端口权重设成3:1同时把座舱侧的端口突发长度从256字节降到128字节这样虽然单次传输小了但减少了bank冲突整体吞吐反而提升了15%。这个参数在文档里写得模棱两可只说“建议按场景调整”实际上就是让你自己试。还有一个容易忽略的点是“虚拟ISP实例的时钟域”。高通允许每个虚拟ISP实例跑在不同的时钟频率上但频率切换是有代价的——需要停掉整个ISP的流水线等PLL重新锁定这个时间大概在200微秒左右。如果你在座舱侧频繁调整时钟频率比如根据场景自动切换高帧率模式那每次切换都会让仪表侧的虚拟ISP实例也跟着停一下。我们当时就遇到过座舱侧切到60fps模式时仪表侧的倒车影像会闪一下黑屏。解决办法是把座舱侧的时钟频率切换策略改成“渐变式”先升到中间频率稳定后再升到目标频率避免直接跳变。这个策略在驱动里用cam_isp_set_clock_ramp接口实现但要注意这个接口在QNX侧和Android侧的实现不完全一样QNX侧需要自己维护一个状态机。最后说点个人经验。做这类虚拟化资源调优别一上来就钻寄存器细节先花半天时间把高通的“Camera Virtualization Overview”文档里的架构图吃透特别是那个“QoS Domain”和“Resource Pool”的关系图。然后一定要在项目早期就验证跨域共享池的配置别等到联调阶段才想起来。还有TZ侧的日志默认是关闭的记得在tzbsp的配置里打开CAM_QOS_DEBUG否则出了问题你只能靠猜。另外如果你们用的是非高通平台比如瑞芯微或者安霸它们的虚拟化方案思路完全不同瑞芯微的RKISP是软虚拟化靠驱动层的调度器做时间片轮转没有硬件级的QoS保障所以别把高通这套经验直接套过去。做影像系统架构平台差异永远是第一位的方案可以借鉴但底层机制必须重新理解。
返回列表