第 19 篇 驱动性能优化与功耗优化实战

目录

开篇先划重点:优化的核心原则

第一部分:驱动性能优化实战

一、驱动代码级优化,最直接、最高效的优化

[1. 中断处理优化,降低中断占用](#1. 中断处理优化,降低中断占用)

[2. 数据拷贝优化,减少内存开销](#2. 数据拷贝优化,减少内存开销)

[3. 锁机制优化,减少死锁和 CPU 自旋](#3. 锁机制优化,减少死锁和 CPU 自旋)

[4. 轮询改事件驱动,彻底杜绝 CPU 空转](#4. 轮询改事件驱动,彻底杜绝 CPU 空转)

二、内核机制优化,提升系统整体性能

[1. 内核抢占与实时性优化](#1. 内核抢占与实时性优化)

[2. DMA 传输优化,解放 CPU](#2. DMA 传输优化,解放 CPU)

[3. 缓存优化,提升内存访问效率](#3. 缓存优化,提升内存访问效率)

[三、RK 平台硬件特性利用,最大化性能](#三、RK 平台硬件特性利用,最大化性能)

第二部分:驱动功耗优化实战

一、驱动级功耗优化,最核心的优化环节

[1. 时钟门控:不用的时钟,全部关掉](#1. 时钟门控:不用的时钟,全部关掉)

[2. 电源域管理:空闲的模块,彻底断电](#2. 电源域管理:空闲的模块,彻底断电)

[3. GPIO 功耗优化,杜绝浮空引脚](#3. GPIO 功耗优化,杜绝浮空引脚)

[4. 中断与唤醒优化,降低系统唤醒次数](#4. 中断与唤醒优化,降低系统唤醒次数)

二、系统级功耗优化

三、硬件级功耗优化

三、优化效果验证与测试方法

[1. 性能测试工具](#1. 性能测试工具)

[2. 功耗测试工具](#2. 功耗测试工具)

结尾说两句


大家好,我是黒漂技术佬。上一篇我们完成了智能门禁的全栈项目实战,很多兄弟后台问:

"佬,我的驱动功能实现了,但是运行起来 CPU 占用很高,还有工业场景里,设备是电池供电的,功耗特别大,续航很短,该怎么优化?"

这个问题非常核心,也是区分新手和资深驱动工程师的关键:功能实现只是入门,性能和功耗优化才是进阶,也是工业级量产产品的核心要求。很多新手写驱动,只关注功能能不能跑通,完全不考虑性能和功耗,结果到了量产阶段,出现 CPU 占用过高、系统卡顿、发热严重、续航太短的问题,根本无法落地。

今天这篇,我就把 RK3568 平台驱动开发的性能优化和功耗优化方法,全部分享给你,从底层驱动代码优化、内核配置优化,到系统级功耗管控,全流程实战,所有方法都可以直接落地到你的项目里。


开篇先划重点:优化的核心原则

在讲具体的优化方法之前,先给大家讲 3 条优化的核心铁律,避免你走弯路:

  1. 先测后优,不瞎优化:优化的第一步,永远是性能和功耗测试,找到瓶颈点,针对性优化,而不是上来就瞎改代码。没有测试数据支撑的优化,都是瞎折腾;
  2. 功能优先,优化为辅:必须先保证驱动功能完全正常、稳定,再做优化。绝对不能为了优化,牺牲功能的稳定性和正确性,工业级产品,稳定永远是第一位的;
  3. 二八原则,抓主要矛盾:80% 的性能损耗和功耗,都是由 20% 的核心代码和模块导致的,重点优化这 20% 的瓶颈点,就能获得 80% 的优化效果,不要在细枝末节上浪费时间。

第一部分:驱动性能优化实战

性能优化的核心目标,是降低驱动的 CPU 占用率、减少中断延迟、提高数据吞吐量、降低系统卡顿,我们从驱动代码优化、内核机制优化、硬件特性利用三个维度,讲最实用的优化方法。

一、驱动代码级优化,最直接、最高效的优化

代码是性能的基础,新手写的驱动,很多性能问题都是代码写的不规范导致的,这部分优化零成本,效果最明显。

1. 中断处理优化,降低中断占用

中断处理是驱动性能的核心瓶颈,尤其是高频中断(比如摄像头、音频、SPI 高速数据传输),中断处理函数执行时间太长,会导致系统实时性下降、CPU 占用升高、甚至丢失中断。

优化方法

  • 严格遵守上半部 + 下半部机制:中断上半部只做最紧急、最耗时最短的工作,比如清除中断标志、记录硬件状态,所有耗时操作,全部放到下半部处理,绝对不能在中断上半部做耗时操作、循环、延时;
  • 选择合适的下半部机制
    • 高频、小数据量、不睡眠的操作,用tasklet,开销比工作队列小;
    • 耗时、需要睡眠的操作,用工作队列 workqueue
    • 超高吞吐率的大数据传输(比如摄像头、网卡),用threaded_irq 线程化中断,把中断处理放到内核线程里执行,不阻塞硬中断,提高系统实时性;
  • 中断合并与节流:对于高频中断(比如传感器 1ms 一次的中断),可以做中断合并,累计一定数量的数据后,再一次处理,减少中断触发的次数;
  • 禁用不必要的中断:不需要的时候,及时关闭中断,比如设备空闲的时候,禁用中断,减少 CPU 的中断开销。

反面案例 vs 优化案例

c

运行

复制代码
// 反面案例:中断上半部里做耗时操作,延时、循环,严重占用CPU
static irqreturn_t bad_irq_handler(int irq, void *dev_id)
{
    int i;
    // 耗时的数据处理,放在中断上半部,完全错误
    for (i = 0; i < 1024; i++) {
        data_buf[i] = read_reg(dev, i);
    }
    msleep(10); // 中断里睡眠,直接导致内核崩溃
    process_data(data_buf); // 耗时的算法处理
    return IRQ_HANDLED;
}

// 优化案例:严格的上半部+下半部,上半部只做最紧急的事
static irqreturn_t good_irq_handler(int irq, void *dev_id)
{
    // 1. 清除中断标志
    clear_irq_flag(dev);
    // 2. 调度下半部,耗时工作交给工作队列
    queue_work(dev->wq, &dev->work);
    // 3. 立刻返回,执行时间极短
    return IRQ_HANDLED;
}

// 下半部:工作队列处理函数,耗时操作都在这里
static void data_work_handler(struct work_struct *work)
{
    int i;
    struct my_dev *dev = container_of(work, struct my_dev, work);
    // 耗时的数据读取和处理,放在下半部
    for (i = 0; i < 1024; i++) {
        dev->data_buf[i] = read_reg(dev, i);
    }
    process_data(dev->data_buf);
}
2. 数据拷贝优化,减少内存开销

用户空间和内核空间的数据拷贝,是驱动里非常常见的性能损耗点,尤其是大数据量传输(比如摄像头、显示、音频),频繁的 copy_from_user/copy_to_user,会导致 CPU 占用急剧升高。

优化方法

  • 减少拷贝次数:尽量一次拷贝完整的数据块,不要循环多次拷贝单个字节,比如要拷贝 1024 字节,一次拷贝完成,不要循环 1024 次,每次拷贝 1 字节;
  • 使用 mmap 内存映射:大数据量传输的场景(比如摄像头、视频采集),用 mmap 实现内核空间和用户空间的内存共享,零拷贝传输,完全避免 copy_from_user/copy_to_user 的开销。这是最高效的方式,摄像头、显示驱动都是用的 mmap;
  • 使用正确的内存分配函数
    • 连续物理内存,用dma_alloc_coherent(),适合 DMA 传输,避免 cache 不一致的问题;
    • 非连续内存,用kmalloc(),小内存分配,速度快,最大不超过 4KB;
    • 大内存分配,用vmalloc(),但是会有 TLB 开销,尽量少用;
  • 避免内存频繁申请释放:驱动初始化的时候,一次性申请好需要的内存缓冲区,驱动运行过程中循环复用,不要频繁的 kmalloc/kfree,减少内存碎片和分配开销。
3. 锁机制优化,减少死锁和 CPU 自旋

锁是用来保护共享资源的,但是用不好,会导致 CPU 自旋等待、死锁、系统卡顿,是新手最容易踩坑的地方。

优化方法

  • 选择正确的锁类型
    • 中断上下文和进程上下文都要访问的共享资源,用自旋锁 spinlock,但是自旋锁持有时间必须极短,不能睡眠;
    • 只有进程上下文访问的共享资源,用互斥锁 mutex,开销比自旋锁小,支持睡眠,适合持有时间较长的场景;
    • 多读少写的场景,用读写锁 rwlock/seqlock,允许多个读者同时访问,提高并发性能;
  • 缩小锁的持有范围:只在访问共享资源的临界区持有锁,访问完成立刻释放,不要把无关的代码放到锁里,减少锁的持有时间;
  • 避免嵌套锁:绝对不要出现锁的嵌套,比如持有锁 A 的时候,申请锁 B,持有锁 B 的时候申请锁 A,必然导致死锁;
  • 禁用抢占和中断的时机 :自旋锁会自动禁用抢占,但是在中断上下文使用自旋锁的时候,必须用spin_lock_irqsave(),禁用本地中断,避免死锁。
4. 轮询改事件驱动,彻底杜绝 CPU 空转

很多新手写驱动,喜欢用轮询的方式读取硬件状态,比如开一个内核线程,每隔 1ms 读一次 GPIO 电平、读一次传感器数据,这会导致 CPU 一直被占用,即使没有数据,CPU 也在空转,性能损耗极大。

优化方法

  • 所有的硬件事件,全部改成中断驱动,只有硬件触发中断的时候,才去处理数据,没有事件的时候,CPU 可以进入休眠,完全不占用资源;
  • 用户空间的事件等待,用poll/epoll + 等待队列 wait_queue实现,没有事件的时候,用户空间线程阻塞休眠,不占用 CPU,有事件的时候,内核唤醒线程处理,彻底杜绝轮询空转。

二、内核机制优化,提升系统整体性能

代码优化完成后,我们可以通过内核配置和机制优化,进一步提升驱动的性能,适配 RK3568 平台的硬件特性。

1. 内核抢占与实时性优化

RK3568 的安卓 SDK 默认的内核配置,是面向消费级产品的,对于工业级高实时性场景(比如运动控制、实时数据采集),可以通过内核配置优化,提升系统的实时性,降低中断和调度延迟:

  • 开启PREEMPT_RT实时补丁:工业级强实时场景,开启 RT 补丁,把 Linux 内核变成硬实时系统,中断延迟可以降到 100us 以内;
  • 开启PREEMPT_VOLUNTARY:自愿内核抢占,适合大多数场景,在不牺牲吞吐量的前提下,降低调度延迟;
  • 关闭DEBUG 相关的配置:内核里的 DEBUG 功能,比如 DEBUG_FS、LOCKDEP、KGDB,会带来很大的性能开销,量产版本必须关闭所有 DEBUG 配置。
2. DMA 传输优化,解放 CPU

对于大数据量的传输(比如音频、视频、SPI 高速数据),用 CPU 轮询拷贝数据,会占用大量的 CPU 资源,而 **DMA(直接内存访问)** 可以让外设直接和内存传输数据,不需要 CPU 干预,传输完成后,触发中断通知 CPU,完全解放 CPU。

RK 平台优化要点

  • RK3568 内置了多个 DMA 控制器,所有的高速外设(I2S、SPI、I2C、CSI)都支持 DMA 传输,驱动里优先使用 DMA 传输,而不是 CPU 轮询的 PIO 模式;
  • 配置 DMA 的突发传输长度,匹配外设的 FIFO 大小,提高 DMA 传输效率,减少中断次数;
  • 使用 DMA 循环缓冲区,适合音频、视频这类连续的数据流传输,减少 DMA 的启动停止开销。
3. 缓存优化,提升内存访问效率

CPU 访问缓存的速度,比访问内存快几十倍,做好缓存优化,能极大提升驱动代码的执行效率。

优化方法

  • 代码和数据对齐:频繁访问的结构体、缓冲区,按 CPU 缓存行对齐(RK3568 的 Cortex-A55 内核,缓存行是 64 字节),避免缓存行伪共享;
  • 连续物理内存:DMA 传输的缓冲区,用dma_alloc_coherent()分配连续的物理内存,避免 cache 和内存的数据不一致,减少 cache 刷新的开销;
  • 减少 cache 刷新:只有在必要的时候,才调用dma_sync_single_for_cpu/device()刷新 cache,不要频繁刷新,带来额外的开销。

三、RK 平台硬件特性利用,最大化性能

RK3568 有很多硬件加速特性,新手往往忽略了这些,用 CPU 去做大量的运算,导致性能很差,我们要充分利用硬件特性,把 CPU 解放出来。

  1. NPU 硬件加速:人脸识别、图像算法、AI 推理,全部放到 NPU 上执行,不要用 CPU 做运算,RK3568 的 1TOPS 算力的 NPU,做 AI 推理的速度,比 CPU 快几十倍;
  2. VPU 硬件编解码:视频的编码解码,用 RK 的硬件 VPU,通过 MPP 框架调用,不要用 CPU 做软编解码,CPU 占用率能从 90% 降到 10% 以内;
  3. RGA2D 硬件加速:图像的缩放、裁剪、格式转换,用 RK 的 RGA2D 硬件加速器,不要用 CPU 做像素运算,速度提升几十倍;
  4. CPU 核心调度优化:把高优先级的驱动线程、中断,绑定到大核上执行,RK3568 是 4 核 Cortex-A55,把实时性要求高的任务,绑定到固定的核心上,避免调度带来的延迟。

第二部分:驱动功耗优化实战

功耗优化,对于电池供电的便携设备、工业物联网设备,是生死攸关的指标,同样的硬件,优化好的设备,续航能提升几倍。功耗优化的核心目标,是在保证功能和性能的前提下,尽可能降低设备的整体功耗,我们从驱动级、系统级、硬件级三个维度,讲最实用的优化方法。

一、驱动级功耗优化,最核心的优化环节

设备的功耗,80% 都是由外设和驱动决定的,驱动级优化是功耗优化的核心,效果最明显。

1. 时钟门控:不用的时钟,全部关掉

RK3568 的每一个外设控制器,都有对应的时钟,时钟在运行的时候,即使外设不工作,也会消耗功耗。时钟门控,就是在外设空闲的时候,关闭它的时钟,需要工作的时候再打开,这是最基础、最高效的功耗优化方法。

优化方法

  • 驱动里使用内核的Runtime PM 运行时电源管理框架,实现外设的时钟自动门控:外设打开的时候,使能时钟;外设关闭 / 空闲的时候,自动关闭时钟;
  • 不用的外设控制器,在设备树里直接设置status = "disabled",内核会直接关闭它的时钟,比如不用 SPI3、I2C4,直接在设备树里禁用;
  • 严格控制时钟频率,不需要高频工作的外设,尽量用低频率,比如 I2C 用 100kHz 就够了,不要用 400kHz,PWM 用 1kHz 就够了,不要用 10kHz。
2. 电源域管理:空闲的模块,彻底断电

比时钟门控更极致的优化,是电源域管理,RK3568 把不同的外设模块,分到了不同的电源域,外设完全空闲的时候,可以把整个电源域关掉,功耗几乎降到 0。

优化方法

  • 驱动里实现系统的suspend/resume 休眠唤醒机制,系统进入休眠的时候,关闭外设的电源,系统唤醒的时候,再重新初始化外设;
  • 对于不常用的外设,比如 RFID、刷卡模块,只有在需要刷卡的时候,才给模块上电,用完立刻断电,不要一直上电;
  • 不用的硬件模块,直接切断供电,比如不用摄像头,就把摄像头的供电 regulator 关掉,不要只关时钟。
3. GPIO 功耗优化,杜绝浮空引脚

很多新手忽略了 GPIO 的功耗,大量浮空的 GPIO 引脚,会导致漏电,增加功耗,尤其是工业场景,引脚很多,累计的功耗非常可观。

优化方法

  • 所有不用的 GPIO 引脚,在设备树里配置为下拉输入模式,避免浮空,减少漏电;
  • 输出模式的 GPIO,空闲的时候,设置为固定电平,不要来回跳变,减少功耗;
  • 输入模式的 GPIO,不需要中断的时候,关闭中断,只在需要的时候开启。
4. 中断与唤醒优化,降低系统唤醒次数

系统频繁的从休眠中唤醒,是功耗高的核心原因之一,每次唤醒,CPU 和各个模块都要上电,消耗大量的功耗。

优化方法

  • 减少不必要的中断触发,比如传感器的采样频率,不需要 1ms 一次,改成 100ms 一次,中断次数减少 100 倍;
  • 合并中断事件,减少唤醒次数,比如多个传感器的数据,可以合并成一次中断唤醒,处理所有数据;
  • 严格控制唤醒源,只有必要的按键、刷卡、网络事件,才能唤醒系统,其他的中断,不能唤醒系统,在设备树里去掉wakeup-source属性。

二、系统级功耗优化

驱动优化完成后,我们可以通过安卓系统的配置,进一步降低整体功耗。

  1. CPU 调频优化 :使用ondemand 调频策略,系统负载低的时候,CPU 自动降到最低频率,负载高的时候,自动升到高频,平衡性能和功耗;电池供电的设备,用powersave策略,优先保证低功耗;
  2. 系统休眠优化:关闭安卓系统里不必要的后台服务、自启应用,减少系统唤醒次数,缩短系统亮屏时间,空闲的时候,自动进入深度休眠;
  3. 网络功耗优化:WiFi 不用的时候,自动关闭,有线网不用的时候,进入低功耗模式,减少网络模块的功耗;
  4. 关闭不必要的外设:不用蓝牙、WiFi、HDMI、USB 的时候,在系统里关闭对应的服务和电源,降低功耗。

三、硬件级功耗优化

功耗优化是软硬件结合的,硬件设计的好坏,直接决定了功耗的下限,这里给大家讲几个硬件设计的功耗优化要点,做产品的时候一定要注意:

  1. 电源方案优化:选择高效率的 DCDC 电源芯片,效率要在 90% 以上,轻载效率高的芯片,适合低功耗场景;LDO 只用于对纹波要求高的场景,因为 LDO 的效率低,功耗大;
  2. 外设供电设计:每个外设模块,都用单独的 MOS 管控制供电,不用的时候,MCU 可以直接切断模块的供电,而不是只靠软件关时钟;
  3. 电平匹配:所有外设都用 3.3V 电平,不要用 5V 电平,降低供电电压,减少功耗;
  4. 硬件防抖:按键、传感器的硬件防抖电路,减少软件的中断触发,降低系统唤醒次数。

三、优化效果验证与测试方法

前面讲过,先测后优,我们必须用专业的工具,测试优化前后的性能和功耗数据,验证优化效果。

1. 性能测试工具

表格

工具 作用 用法
top/htop 查看 CPU 占用率,看驱动的内核线程 / 中断的 CPU 占用 top -d 1,实时查看 CPU 占用
vmstat 查看系统的上下文切换、中断次数、内存使用 vmstat 1,每秒刷新一次
perf 内核性能分析工具,定位 CPU 占用高的函数 perf top,实时查看 CPU 占用最高的函数
ftrace 内核函数跟踪工具,分析函数执行时间、中断延迟 跟踪驱动的函数执行时间,定位瓶颈
cyclictest 测试系统的中断和调度延迟,验证实时性优化效果 cyclictest -m -t1 -p 99,测试最大延迟

2. 功耗测试工具

表格

工具 作用 用法
功率计 测量整机的实时功耗,看整机的平均功耗和峰值功耗 串在电源输入端,记录优化前后的功耗数据
powertop Linux 功耗分析工具,定位系统唤醒源、功耗高的模块 powertop,查看每个模块的功耗和唤醒次数
/sys/class/power_supply/ 查看电池的实时电流、电压、功耗 cat /sys/class/power_supply/battery/current_now,查看实时电流
kernelshark 可视化分析系统的唤醒、调度、中断事件,定位频繁唤醒的原因 配合 ftrace 使用,可视化分析唤醒源

结尾说两句

这篇文章,我们把驱动性能优化和功耗优化的核心方法,从代码级、内核级、系统级、硬件级,全部分享给你了,这些都是工业级量产产品必须掌握的技能。功能实现只是入门,能把驱动做到高性能、低功耗、高稳定,才是真正的资深驱动工程师。

下一篇,我们进入 RK 平台的核心加速模块,NPU / 硬件编解码驱动适配与安卓调用,教你怎么用 RK3568 的 NPU 做 AI 推理,用 VPU 做硬件编解码,充分发挥 RK 平台的硬件优势。

我是黒漂技术佬,关注我,带你零基础入门 RK 安卓驱动开发,不踩坑。有任何性能和功耗优化的问题,评论区留言,我都会一一回复。

相关推荐
91刘仁德3 小时前
C++ 内存管理
android·c语言·数据结构·c++·经验分享·笔记·算法
道一云黑板报3 小时前
技术拆解:AI低代码架构设计与全链路落地实现
人工智能·驱动开发·低代码·ai·企业微信·ai编程·代码规范
小强开学前3 小时前
自定义 Drawable 实现任意高度纯圆角背景及玻璃效果
android
秃了也弱了。4 小时前
ElasticSearch:优化案例实战解析(持续更新)
android·java·elasticsearch
恋猫de小郭4 小时前
Kotlin 在 2.0 - 2.3 都更新了什么特性,一口气带你看完这两年 Kotlin 更新
android·前端·flutter
LXY_BUAA4 小时前
《嵌入式操作系统》_高级字符设备驱动_20260316
linux·运维·服务器·驱动开发
墨狂之逸才5 小时前
React Native 移动项目目录导致的 Android 编译失败问题及解决方案
android·react native
feng一样的男子5 小时前
住在手机里的“小龙虾” (OpenClaw):接入本地模型,解决记忆“装死”顽疾
android·ai·智能手机·openclaw
hongtianzai5 小时前
MySQL中between and的基本用法
android·数据库·mysql