二、多核处理器基础:什么是多核处理器、对称多处理(SMP)与非对称多处理(AMP)、MTK big.LITTLE架构详解
好,咱们进入正题。这一章我打算聊聊多核处理器的基础概念。说实话,我刚入行那会儿,对多核的理解就是“一个芯片里塞了好几个CPU核心”。后来做MTK平台的项目,踩了不少坑,才真正搞明白里面的门道。
2.1 什么是多核处理器?
多核处理器,说白了就是把两个或更多的独立计算核心集成到同一个芯片上。每个核心都有自己的L1缓存,共享L2或L3缓存。它们可以同时执行不同的任务。
你可能会问:“那跟单核处理器有啥本质区别?”
嗯,区别大了。单核处理器靠提升主频来提速,但功耗和发热是硬伤。多核处理器则靠“人多力量大”——每个核心跑得不用太快,但合起来干活效率高。我在一个平板项目里就遇到过,单核跑1.5GHz烫得能煎鸡蛋,换成四核1.2GHz,温度降了20度,性能反而提升了30%。
核心要点:多核处理器不是简单地把核心堆在一起,而是通过共享资源、协同调度来实现性能与功耗的平衡。
2.2 对称多处理(SMP)与非对称多处理(AMP)
这两个概念,我当年花了整整一周才吃透。咱们一个一个来。
2.2.1 对称多处理(SMP)
SMP,全称Symmetric Multi-Processing。所有核心地位平等,共享同一块内存空间,操作系统统一调度。你写一个多线程程序,系统会自动把线程分配到不同的核心上跑。
优点很明显:
- 编程简单,开发者不用操心核心分配
- 负载均衡好,系统自动调度
- 兼容性好,现有软件基本都能跑
缺点呢?
- 所有核心共享内存总线,高并发时容易成为瓶颈
- 功耗控制不够精细,不适合对功耗敏感的场景
我在MT6739平台上做过一个SMP调优项目。当时发现四个核心全开时,内存带宽被占满,导致GPU帧率掉得厉害。后来通过限制核心频率和绑定中断亲和性,才把问题解决。
2.2.2 非对称多处理(AMP)
AMP,全称Asymmetric Multi-Processing。核心之间地位不同,有的负责高性能计算,有的负责低功耗后台任务。每个核心可以跑不同的操作系统,或者同一个操作系统的不同实例。
举个例子:
- 大核跑Linux,处理复杂的UI渲染
- 小核跑RTOS,处理传感器数据采集
AMP的优势:
- 功耗控制极好,小核干小活,大核干大活
- 实时性强,关键任务不会被其他任务干扰
但坑也不少:
- 编程复杂,你得手动管理核心间的通信
- 调试困难,两个系统之间的同步问题让人头大
避坑指南:我曾经在一个AMP项目中,大核和小核共享一个UART外设。结果两边同时写数据,导致数据错乱。后来加了信号量才搞定。记住:共享资源一定要做好互斥保护。
2.3 MTK big.LITTLE架构详解
big.LITTLE,这是ARM公司提出来的混合架构。MTK把它玩出了花。说白了,就是把高性能的“大核”和低功耗的“小核”组合在一起。
以MT6765为例:
- 4个Cortex-A53小核(最高1.5GHz)
- 4个Cortex-A53大核(最高2.3GHz)
等等,你可能注意到了——都是A53?没错,MTK早期方案里大小核用的是同一种架构,只是频率和电压不同。后来才引入Cortex-A75/A55这样的异构组合。
2.3.1 三种工作模式
| 模式 | 描述 | 适用场景 |
|---|---|---|
| Cluster Switching | 同一时间只能使用大核簇或小核簇,不能混用 | 简单任务切换,功耗敏感场景 |
| In-Order Scheduling | 系统根据负载动态调度任务到大核或小核 | 日常使用,兼顾性能与功耗 |
| Global Task Scheduling | 所有核心同时可用,系统智能分配任务 | 高性能场景,如游戏、视频编辑 |
我个人习惯用Global Task Scheduling模式。虽然功耗高一点,但用户体验好。记得有一次做视频播放优化,用Cluster Switching模式,切换核心时画面会卡顿半秒。换成Global Task Scheduling后,流畅度明显提升。
2.3.2 MTK的调度策略
MTK在Linux内核里加了自己的调度器——HMP(Heterogeneous Multi-Processing)。它比标准的CFS调度器更智能,能识别任务的特性:
- 前台交互任务 → 优先分配到大核
- 后台服务任务 → 分配到小核
- 突发高负载 → 临时唤醒大核
这里有个小技巧:你可以通过/sys/devices/system/cpu/下的节点手动控制核心状态。比如:
# 查看当前在线核心
cat /sys/devices/system/cpu/online
# 手动关闭某个核心
echo 0 > /sys/devices/system/cpu/cpu3/online
# 设置大核最小频率
echo 1000000 > /sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq
经验之谈:调试阶段别直接改这些节点,容易把系统搞崩。我建议先在adb shell里测试,确认没问题再写到init脚本里。
2.3.3 实际项目中的坑
嗯,这里得说说我踩过的坑。
第一个坑:大小核切换延迟。在MT6771平台上,从大核切到小核大约需要2-3ms。如果任务对延迟敏感,比如音频处理,这2ms就可能导致爆音。解决方案是把音频线程绑定到大核上:
# 绑定进程到CPU4-7(大核)
taskset -p 0xf0 <PID>
第二个坑:功耗估算不准。MTK的功耗模型默认假设小核功耗是大核的1/3。但实际测试发现,小核跑满负载时功耗接近大核的60%。所以别盲目相信默认参数,一定要实测。
第三个坑:缓存一致性。big.LITTLE架构下,大核和小核的L2缓存是独立的。如果一个任务在大核上修改了数据,然后切到小核上继续跑,小核可能读到旧数据。MTK通过硬件一致性总线解决了这个问题,但如果你用DMA直接访问内存,还是得小心。
2.4 小结
这一章咱们聊了多核处理器的基本概念,SMP和AMP的区别,以及MTK big.LITTLE架构的细节。说白了,多核开发的核心就是“把合适的任务放到合适的核心上”。
下一章我会讲MTK平台的任务调度机制,包括CFS调度器、HMP调度器,以及如何通过cgroup做资源隔离。到时候咱们再细聊。
对了,如果你在项目中遇到大小核调度的问题,欢迎来公众号找我聊聊。我平时也会分享一些MTK开发的实战经验。
课后思考:假设你有一个实时音频处理任务和一个后台下载任务,你会怎么分配核心?为什么?