第2章:CPU架构详解:Kryo 485核心、大小核调度策略、L1/L2/L3缓存层次
好,咱们直接切入正题。SA8155这颗芯片,CPU部分用的是高通自研的Kryo 485架构。说实话,我第一次拿到这颗芯片的datasheet时,第一反应是——这不就是ARM Cortex-A76的魔改版吗?
嗯,确实如此。Kryo 485本质上就是基于ARM Cortex-A76的定制化实现。高通在微架构层面做了一些自己的优化,但指令集、流水线深度、乱序执行窗口这些核心参数,跟公版A76基本一致。我习惯把它理解为「高通特调版A76」。
2.1 Kryo 485核心:三丛集架构
SA8155的CPU部分采用了1+3+4的三丛集设计。具体来说:
- 1个超大核:Kryo 485 Gold Prime,最高频率2.96GHz
- 3个大核:Kryo 485 Gold,最高频率2.42GHz
- 4个小核:Kryo 485 Silver,最高频率1.8GHz
你可能会问:为什么同样是Gold核心,频率还不一样?
我在项目中遇到过这个问题。其实超大核和大核的物理设计完全一样,只是高通在芯片出厂时做了binning筛选。体质好的那颗核心,被允许跑到更高频率,这就是所谓的「Prime Core」。说白了,就是挑了个尖子生当班长。
关键参数速览:
| 核心类型 | 架构 | 最高频率 | L1 I/D缓存 | L2缓存 |
|---|---|---|---|---|
| 1× Prime | Kryo 485 Gold | 2.96 GHz | 64KB / 64KB | 512KB |
| 3× Gold | Kryo 485 Gold | 2.42 GHz | 64KB / 64KB | 256KB |
| 4× Silver | Kryo 485 Silver | 1.80 GHz | 32KB / 32KB | 128KB |
2.2 大小核调度策略:EAS与WALT
讲调度之前,我想先聊个背景。车载系统和手机系统不一样,手机用户在乎的是「刷微博卡不卡」,车载用户在乎的是「导航会不会延迟」、「语音助手响应快不快」。所以调度策略必须更保守、更可预测。
SA8155的调度框架基于Linux内核的EAS(Energy Aware Scheduling)。EAS的核心思想很简单:让合适的任务跑到合适的核心上。
- 轻量级任务(如CAN总线轮询、GPIO中断)→ 丢给小核跑,省电
- 中负载任务(如导航渲染、音频处理)→ 丢给大核跑,平衡功耗与性能
- 重负载任务(如启动动画、高帧率UI)→ 丢给超大核跑,瞬间爆发
但这里有个坑。我曾经在调试一个车载仪表盘项目时,发现导航应用偶尔会出现卡顿。查了半天,发现是EAS的负载预测不准——它把导航的渲染线程误判为轻负载,丢到了小核上。结果小核扛不住,帧率直接掉到20fps。
避坑指南:
我曾经踩过这个坑。如果你在车载项目中发现某些关键线程被错误调度到小核,可以尝试以下方法:
- 使用
sched_setaffinity()手动绑定CPU亲和性 - 或者通过cgroup的
cpu.uclamp机制设置最小频率要求 - 再或者,直接修改内核的
schedutilgovernor参数
另外,高通在EAS基础上还加了自己的WALT(Window Assisted Load Tracking)算法。WALT比标准的PELT(Per-Entity Load Tracking)更激进,它对突发负载的响应更快。你想想看,车载场景下用户突然点一下屏幕,系统必须立刻响应,WALT正好适合这种场景。
2.3 L1/L2/L3缓存层次
缓存这东西,说白了就是「数据的中转站」。CPU跑得飞快,但内存太慢,中间必须靠缓存来缓冲。
SA8155的缓存层次是这样的:
- L1缓存:每个核心私有。指令缓存和数据缓存分开。Gold核心各64KB,Silver核心各32KB。
- L2缓存:每个核心私有。Prime核心512KB,Gold核心256KB,Silver核心128KB。
- L3缓存:所有核心共享。总共2MB。
这里有个细节值得注意。Prime核心的L2缓存是512KB,比其他Gold核心大一倍。为什么?因为Prime核心要处理最重的负载,更大的L2可以减少对L3和内存的访问次数。我在做性能分析时发现,某些场景下Prime核心的L2 miss率比Gold核心低了将近15%。
注意:
L3缓存是所有核心共享的,这意味着如果某个核心疯狂刷缓存,其他核心的性能会受到影响。我在项目中遇到过一个问题:一个后台OTA下载线程频繁写内存,导致L3缓存被污染,前台导航应用的帧率直接掉了一半。解决方案是把OTA线程的缓存策略改成non-temporal,绕过缓存直接写内存。
关于缓存一致性,SA8155使用的是MESI协议的一个变种。嗯,这里不展开讲协议细节了,你只需要知道:当两个核心同时访问同一块内存时,硬件会自动保证数据的一致性。但代价是——如果两个核心频繁争抢同一块数据,性能会急剧下降。这就是所谓的「伪共享(False Sharing)」问题。
实战技巧:
我习惯在编写多线程代码时,把每个线程的私有数据按64字节对齐。因为缓存行(cache line)通常是64字节,对齐后可以避免两个线程的变量落在同一个缓存行里,从而避免伪共享。
// 示例:按64字节对齐的结构体
struct __attribute__((aligned(64))) thread_data {
int counter;
char padding[60]; // 填充到64字节
};
2.4 性能调优实战建议
最后,我总结几条在SA8155上做CPU性能调优的经验:
- 先看缓存命中率。用perf stat或者高通的QPST工具,看看L1/L2/L3的miss率。如果L3 miss率超过5%,说明内存访问模式有问题,优先优化数据布局。
- 别盲目绑核。很多人一上来就把所有线程绑到Prime核心上,结果Prime核心过热降频,性能反而更差。我建议把最关键的1-2个线程绑到Prime核心,其他线程让EAS自己调度。
- 注意大小核切换延迟。当一个线程从小核迁移到大核时,L1/L2缓存全部失效,需要重新加载数据。这个切换延迟大约在几十微秒级别。如果线程频繁切换核心,性能反而会下降。
- 善用cpuidle。车载系统对功耗有严格要求,但也不能让核心频繁进入深度睡眠。我一般把idle state设置为C1(浅睡眠),这样唤醒延迟只有几微秒。
嗯,CPU架构这块就先聊到这儿。下一章咱们讲GPU,SA8155的Adreno 640也是个有意思的东西。