3. 多核同步与低功耗的冲突:同步等待导致的功耗浪费、锁竞争与功耗峰值、缓存一致性协议(MESI)的功耗影响

多核系统里,同步和低功耗就像一对冤家。你想想看,核多了,干活快了,但协调它们却要付出代价。这个代价,很多时候就是功耗。

我刚开始做多核项目时,天真地以为只要把任务分给几个核,功耗自然就降下来了。结果一测,好家伙,功耗比单核还高。问题出在哪?就出在同步上。

3.1 同步等待导致的功耗浪费

最简单的同步方式是什么?自旋锁。一个核在等另一个核释放资源,它就在那空转。空转意味着什么?CPU 还在跑,指令还在取,流水线还在动,但没干任何有用的活。

这种功耗浪费,我称之为“空转功耗”。

关键数据:一个 Cortex-A53 核在自旋等待时,功耗大约是满负荷运行的 60%-70%。如果系统里有 4 个核都在等,那浪费的功耗相当可观。

为什么会这样?因为自旋锁的实现通常是一个循环,不断读取共享内存中的标志位。这个循环本身就在消耗动态功耗。更糟糕的是,它还会导致缓存行 bouncing,进一步增加功耗。

我曾经在一个项目中,发现一个核在等另一个核处理完数据,等了整整 2 毫秒。2 毫秒在嵌入式系统里可不短。那个等待的核,功耗一直维持在 80mW 左右。如果换成睡眠等待,功耗能降到 1mW 以下。差距有多大?80 倍。

我的建议:能用睡眠等待,就别用自旋等待。实在要用自旋,也要加个超时机制,别让核在那死等。

3.2 锁竞争与功耗峰值

锁竞争带来的问题更隐蔽。它不光是性能问题,还是功耗问题。

当多个核同时竞争一把锁时,会发生什么?

  • 每个核都在尝试获取锁
  • 获取失败的核会重试
  • 重试过程中,缓存一致性协议在疯狂工作
  • 总线带宽被占满

结果就是:功耗峰值瞬间飙升。我见过一个极端案例,8 个核同时竞争一个全局锁,系统瞬时功耗达到了平均功耗的 3 倍。这个峰值如果持续时间长,电源管理单元可能会误判,导致电压调节器输出不稳定。

锁竞争场景 平均功耗 峰值功耗 持续时间
无竞争 100mW 120mW —
2 核竞争 150mW 220mW ~10μs
4 核竞争 210mW 350mW ~20μs
8 核竞争 320mW 580mW ~50μs

你看这个表,核数越多,竞争越激烈,功耗峰值越高。而且这个峰值不是一次性的,是反复出现的。每次锁竞争,都是一次功耗冲击。

避坑指南:我曾经在一个项目中,锁竞争导致的功耗峰值触发了芯片的过流保护,系统直接复位了。排查了三天才发现是锁竞争的问题。从那以后,我设计系统时一定会做锁竞争分析,尤其是对功耗敏感的场合。

3.3 缓存一致性协议(MESI)的功耗影响

MESI 协议,说白了就是让多个核的缓存保持一致的一套规则。每个缓存行有四种状态:Modified、Exclusive、Shared、Invalid。

状态切换是要花代价的。每次状态变化,都意味着总线事务。总线事务意味着什么?功耗。

我画了一张图,帮你理解 MESI 状态切换与功耗的关系:

MESI 状态切换与功耗关系 M (Modified) E (Exclusive) S (Shared) I (Invalid) 读命中 读共享 失效 状态切换的功耗代价 • M → I:写回主存 + 失效通知,功耗最高 • E → S:读共享请求,功耗中等 • S → I:失效监听,功耗较低 • I → E/S:缓存填充,功耗取决于是否命中 核心结论 1. 状态切换越频繁,总线事务越多,功耗越高 2. 共享数据越多,S 状态越多,监听功耗越大 3. 伪共享是最大的功耗杀手,要尽量避免

从这张图你能看到,MESI 状态切换不是免费的。每次状态变化,都伴随着总线事务。总线事务越多,功耗越高。

这里我要特别提一下伪共享。伪共享是什么?两个核访问不同的变量,但这两个变量恰好在同一个缓存行里。结果就是,明明没有真正的数据竞争,但缓存行却在两个核之间来回 bouncing。

我遇到过最夸张的一个案例:一个数据结构里有两个计数器,分别被两个核频繁更新。两个计数器在同一个缓存行里。结果呢?缓存行每纳秒都在 bouncing,总线带宽被占满,功耗比预期高了 40%。

我的建议:对于频繁更新的共享数据,用缓存行对齐。把不同核访问的数据放到不同的缓存行里。C11 标准里有 alignas 关键字,可以用起来。

3.4 如何平衡同步与低功耗

说了这么多问题,那怎么解决?我总结了几条经验:

  1. 减少同步粒度:能用局部锁,就别用全局锁。锁的粒度越小,竞争越少,功耗越低。
  2. 使用无锁数据结构:在合适的场景下,用原子操作代替锁。原子操作不会导致缓存行 bouncing,功耗更低。
  3. 合理选择同步机制:短等待用自旋锁,长等待用信号量。自旋锁的等待时间不要超过 10μs。
  4. 缓存行对齐:避免伪共享,把不同核访问的数据放到不同缓存行。
  5. 使用硬件同步原语:有些芯片有硬件同步单元,比软件锁效率高得多。

经验之谈:我做过一个项目,把全局锁拆成 4 个局部锁,功耗直接降了 25%。有时候,简单的设计改动就能带来巨大的收益。

嗯,同步和低功耗的冲突,说白了就是“协调成本”的问题。协调得越好,成本越低。但完全消除协调成本是不可能的,我们只能尽量优化。