69

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

我正在使用 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 与高速缓存行对齐。

4

7 回答 7

94

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

$ getconf LEVEL1_DCACHE_LINESIZE
64

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

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

在运行时sysconf(_SC_LEVEL1_DCACHE_LINESIZE)可用于获取 L1 缓存大小。

于 2011-09-02T14:24:19.050 回答
40

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

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

于 2011-09-02T09:50:52.420 回答
13

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

grep cache_alignment /proc/cpuinfo
于 2012-06-02T07:17:00.343 回答
9

没有完全可移植的方法来获取缓存线大小。但是,如果您使用的是 x86/64,则可以调用该cpuid指令来获取您需要了解的有关缓存的所有信息 - 包括大小、缓存行大小、级别数等……

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

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

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

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

于 2011-09-02T14:52:34.033 回答
8

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

于 2011-09-02T09:56:06.327 回答
3

这是我制作的一张桌子,上面有大多数 Arm/Intel 处理器。您可以在定义常量时将其用作参考,这样您就不必为所有架构概括缓存线大小。

对于 C++,希望我们很快就会看到硬件接口大小,这应该是获取此信息的准确方法(假设您告诉编译器您的目标架构)。

于 2019-11-29T11:36:40.343 回答
2

如果有人对如何在 C++ 中轻松地做到这一点感到好奇,我已经构建了一个库,其中包含一个CacheAligned<T>类,该类处理确定缓存行大小以及对象的对齐方式T,通过调用.Ref()您的CacheAligned<T>对象来引用。Aligned<typename T, size_t Alignment>如果您事先知道缓存行大小,或者只是想坚持使用非常常见的值 64(字节),您也可以使用。

https://github.com/NickStrupat/Aligned

于 2015-01-23T06:22:17.973 回答