Cache 系列文章8:伪共享

本文讨论了多核系统中由于全局变量伪共享导致的cache颠簸问题,介绍了MESI协议的作用,以及通过cacheline对齐内存地址来避免伪共享的解决方案。在Linuxkernel中,__cacheline_aligned_in_smp宏用于处理这种情况。
摘要由CSDN通过智能技术生成

我们知道kernel地址空间是所有进程共享的,所以kernel空间的全局变量,任何进程都可以访问。假设有2个全局变量global_A和global_B(类型是long),它们在内存上紧挨在一起,如下图所示,假设cache line size是64Bytes。所以global_A和global_B如果同时load到Cache中,一定是落在同一行cache line。就像下面这样。

现在我们知道多核Cache一致性由MESI协议保证。有了这些基础之后,我们现在来思考一个问题,如果我们的系统有2个CPU,每个CPU上运行完全不相干的两个进程task_A和task_B。task_A只会修改global_A变量,task_B只会修改global_B变量。会有什么问题吗?

我们遇到什么问题

最初全局变量global_A和global_B都不在cache中缓存,如下图示意。task_A绑定CPU0运行,task_B绑定CPU1运行。task_A和task_B按照下面的次序分别修改或读取全局变量global_A和global_B。

a) CPU0读取global_A,global_A的数据被缓存到CPU0的私有L1 Cache。由于Cache控制器是以cache line为单位从内存读取数据,所以顺便就会把global_B变量也缓存到Cache。并将cache line置为Exclusive状态。

b) CPU1读取global_B变量,由于global_B被CPU0私有Cache缓存,所以CPU0的L1 Cache负责返回global_B数据到CPU1的L1 Cache。同样global_A也被缓存。此时CPU0和CPU1的cache line状态变成Shared状态。

c) CPU0现在需要修改global_A变量。CPU0发现cache line状态是Shared,所以需要发送invalid消息给CPU1。CPU1将global_A对应的cache line无效。然后CPU0的cache line状态变成Modified并且修改global_A。

d) CPU1现在需要修改global_B变量。此时global_B变量并没有缓存在CPU1私有Cache。所以CPU1会发消息给CPU0,CPU0将global_B数据返回给CPU1。并且会invalid CPU0的cache line。然后global_B对应的CPU1 cache line变成Modified状态,此时CPU1就可以修改global_B了。

如果CPU0和CPU1就这样持续交替的分别修改全局变量global_A和global_B,就会重复c)和d)。意识到问题所在了吗?这就是典型的cache颠簸问题。我们仔细想想,global_A和global_B其实并没有任何的关系,却由于落在同一行cache line的原因导致cache颠簸。我们称这种现象为伪共享(false sharing)。global_A和global_B之间就是伪共享关系,实际并没有共享。我们如何解决伪共享问题呢?

如何解决伪共享

既然global_A和global_B由于在同一行cache line导致了伪共享问题,那么解决方案也很显然易见,我们可以让global_A和global_B不落在一个cache line,这样就可以解决问题。不落在同一行cache line的方法很简单,使global_A和global_B的内存地址都按照cache line size对齐,相当于以空间换时间。浪费一部分内存,换来了性能的提升。当我们把global_A和global_B都cache line size对齐后,我们再思考上面的问题。此时CPU0和CPU1分别修改global_A和global_B互不影响。global_A和global_B对应的cache line状态可以一直维持Modified状态。这样MESI协议就不会在两个CPU间不停的发送消息。降低了带宽压力。

实际应用

在Linux kernel中存在__cacheline_aligned_in_smp宏定义用于解决false sharing问题。

#ifdef CONFIG_SMP
#define __cacheline_aligned_in_smp __cacheline_aligned
#else
#define __cacheline_aligned_in_smp
#endif

我们可以看到在UP(单核)系统上,宏定义为空。在MP(多核)系统下,该宏是L1 cach line size。针对静态定义的全局变量,如果在多核之间竞争比较严重,为了避免影响其他全局变量,可以采用上面的宏使变量cache line对齐,避免false sharing问题。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值