为了防止错误共享,我想将数组的每个元素对齐到缓存行。所以首先我需要知道缓存行的大小,因此我为每个元素分配了大量的字节。其次,我希望数组的开始与高速缓存行对齐。
我使用的是Linux和8核x86平台。首先,我如何找到缓存行大小。其次,如何与C中的缓存行对齐。我正在使用gcc编译器。
因此,假设缓存行大小为64,结构将遵循。
element[0] occupies bytes 0-63
element[1] occupies bytes 64-127
element[2] occupies bytes 128-191
等等,假设当然0-63与高速缓存行对齐。
答案 0 :(得分:75)
我使用的是Linux和8核x86平台。首先,我如何找到缓存行大小。
$ getconf LEVEL1_DCACHE_LINESIZE
64
将值作为宏定义传递给编译器。
$ gcc -DLEVEL1_DCACHE_LINESIZE=`getconf LEVEL1_DCACHE_LINESIZE` ...
在运行时sysconf(_SC_LEVEL1_DCACHE_LINESIZE)
可用于获取L1缓存大小。
答案 1 :(得分:32)
要了解尺寸,您需要使用处理器的文档查找它,但是没有编程方法。然而,从好的方面来看,大多数缓存行都是标准大小,基于intels标准。在x86缓存行上是64字节,但是,为了防止错误共享,您需要遵循您所针对的处理器的指导原则(intel在其基于netburst的处理器上有一些特殊说明),通常需要为此对齐64个字节(英特尔表示你还应该避免跨越16字节边界)。
要在C或C ++中执行此操作,需要使用标准aligned_alloc
函数或其中一个编译器特定说明符,例如__attribute__((align(64)))
或__declspec(align(64))
。要在结构中的成员之间填充以将它们拆分到不同的缓存行,您需要插入一个足够大的成员以将其与下一个64字节boundery对齐
答案 2 :(得分:9)
没有完全可移植的方式来获取缓存行大小。但如果您使用的是x86 / 64,则可以调用cpuid
指令来获取有关缓存的所有信息 - 包括大小,缓存行大小,多少级别等等。
http://softpixel.com/~cwright/programming/simd/cpuid.php
(向下滚动一下,该页面是关于SIMD的,但它有一个获取缓存行的部分。)
至于对齐数据结构,也没有完全可移植的方法。 GCC和VS10有不同的方法来指定结构的对齐方式。 “破解”它的一种方法是使用未使用的变量填充结构,直到它与您想要的对齐方式匹配。
为了对齐你的mallocs(),所有主流编译器也都有为此目的对齐的malloc函数。
答案 3 :(得分:9)
另一种简单的方法是只使用/ proc / cpuinfo:
cat / proc / cpuinfo | grep cache_alignment
答案 4 :(得分:8)
posix_memalign or valloc可用于将分配的内存与高速缓存行对齐。
答案 5 :(得分:2)
如果有人对如何在C ++中轻松完成此操作感到好奇,我已经构建了一个带有CacheAligned<T>
类的库,该类处理确定缓存行大小以及{{1}的对齐方式通过在T
对象上调用.Ref()
引用的对象。如果您事先知道缓存行大小,或者只想坚持使用非常常见的64(字节)值,也可以使用CacheAligned<T>
。
答案 6 :(得分:1)
Here's a table我做到了,上面装有大多数Arm / Intel处理器。在定义常量时,可以将其用作参考,这样就不必泛化所有体系结构的缓存行大小。
希望对于C ++,我们很快会看到hardware interface size,它应该是获取此信息的准确方法(假设您告诉编译器您的目标体系结构)。