Cacheline优化
原理
CPU标识Cache中的数据是否为有效数据不是以内存位宽为单位,而是以Cacheline为单位。这个机制可能会导致伪共享(false sharing)现象,从而使得CPU的Cache命中率变低。出现伪共享的常见原因是高频访问的数据未按照Cacheline大小对齐。
Cache空间大小划分成不同的Cacheline,示意图如图1所示。readHighFreq虽然没有被改写,且在Cache中,在发生伪共享时,也是从内存中读。
例如以下代码定义两个变量,会在同一个Cacheline中,Cache会同时读入:
int readHighFreq, writeHighFreq
其中readHighFreq是读频率高的变量,writeHighFreq为写频率高的变量。writeHighFreq在一个CPU core里面被改写后,这个cache中对应的Cacheline长度的数据被标识为无效,也就是readHighFreq被CPU core标识为无效数据,虽然readHighFreq并没有被修改,但是CPU在访问readHighFreq时,依然会从内存重新导入,出现伪共享导致性能降低。
鲲鹏920和x86的Cacheline大小不一致,可能会出现在x86上优化好的程序在鲲鹏920上运行时的性能偏低的情况,需要重新修改业务代码数据内存对齐大小。x86 L3 cache的Cacheline大小为64字节,鲲鹏920的Cacheline为128字节。
修改方式
- 修改业务代码,使得读写频繁的数据以Cacheline大小对齐,修改方法可参考:
- 使用动态申请内存的对齐方法:
int posix_memalign(void **memptr, size_t alignment, size_t size)
调用posix_memalign函数成功时会返回size字节的动态内存,并且这块内存的起始地址是alignment的倍数。
- 局部变量可以采用填充的方式:
int writeHighFreq; char pad[CACHE_LINE_SIZE - sizeof(int)];
代码中CACHE_LINE_SIZE是服务器Cacheline的大小,pad变量没有用处,用于填充writeHighFreq变量余下的空间,两者之和是CacheLine大小。
- 使用动态申请内存的对齐方法:
- 部分开源软件代码中有Cacheline的宏定义,修改宏的值即可。如在impala使用CACHE_LINE_SIZE宏来表示目标平台的Cacheline大小。
父主题: 优化方法