对齐缓存行并了解缓存行大小

问题描述 投票:0回答:7

为了防止错误共享,我想将数组的每个元素与缓存行对齐。因此,首先我需要知道缓存行的大小,因此我为每个元素分配相应的字节数。其次,我希望数组的开头与缓存行对齐。

我使用的是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 与缓存行对齐。

c linux caching cpu-architecture memory-alignment
7个回答
94
投票

我使用的是Linux和8核x86平台。首先如何找到缓存行大小。

$ getconf LEVEL1_DCACHE_LINESIZE
64

将值作为宏定义传递给编译器。

$ gcc -DLEVEL1_DCACHE_LINESIZE=`getconf LEVEL1_DCACHE_LINESIZE` ...

在运行时

sysconf(_SC_LEVEL1_DCACHE_LINESIZE)
可用于获取 L1 缓存大小。


42
投票

要了解尺寸,您需要使用处理器的文档进行查找,据我所知,没有编程方法可以做到这一点。然而,从好的方面来说,大多数缓存行都是基于英特尔标准的标准大小。在 x86 上,缓存行为 64 字节,但是,为了防止错误共享,您需要遵循目标处理器的指导原则(英特尔对其基于 netburst 的处理器有一些特殊说明),通常您需要为此对齐到 64 字节(英特尔指出您还应该避免跨越 16 字节边界)。

要在 C 或 C++ 中执行此操作,需要使用标准

aligned_alloc
函数或编译器特定说明符之一,例如
__attribute__((aligned(64)))
__declspec(align(64))
。要在结构中的成员之间填充以将它们拆分到不同的缓存行,您需要插入一个足够大的成员以将其与下一个 64 字节边界对齐


14
投票

另一种简单的方法是只获取 /proc/cpuinfo:

grep cache_alignment /proc/cpuinfo

9
投票

没有完全可移植的方法来获取缓存行大小。但如果您使用的是 x86/64,则可以调用

cpuid
指令来获取您需要了解的有关缓存的所有信息 - 包括大小、缓存行大小、多少级等...

http://softpixel.com/~cwright/programming/simd/cpuid.php

(向下滚动一点,该页面是关于 SIMD 的,但其中有一个部分获取缓存行。)

至于对齐数据结构,也没有完全可移植的方法来做到这一点。 GCC 和 VS10 有不同的方法来指定结构的对齐方式。 “破解”它的一种方法是用未使用的变量填充结构,直到它与您想要的对齐方式匹配。

为了对齐你的 malloc(),所有主流编译器也为此目的对齐了 malloc 函数。


8
投票

posix_memalignvalloc 可用于将分配的内存与缓存行对齐。



2
投票
如果有人对如何在 C++ 中轻松完成此操作感到好奇,我已经构建了一个带有

CacheAligned<T>

 类的库,该类处理确定缓存行大小以及 
T
 对象的对齐方式,通过调用 
.Ref() 进行引用
 在您的 
CacheAligned<T>
 对象上。如果您事先知道缓存行大小,或者只想坚持使用非常常见的值 64(字节),您也可以使用 
Aligned<typename T, size_t Alignment>

https://github.com/NickStrupat/Aligned

© www.soinside.com 2019 - 2024. All rights reserved.