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

Met*_*est 58 c linux caching computer-architecture memory-alignment

为了防止错误共享,我想将数组的每个元素对齐到缓存行.所以首先我需要知道缓存行的大小,因此我为每个元素分配了大量的字节.其次,我希望数组的开始与高速缓存行对齐.

我使用的是Linux和8核x86平台.首先,我如何找到缓存行大小.其次,如何与C中的缓存行对齐.我正在使用gcc编译器.

因此,假设高速缓存行大小为64,结构将遵循.

element[0] occupies bytes 0-63
element[1] occupies bytes 64-127
element[2] occupies bytes 128-191
Run Code Online (Sandbox Code Playgroud)

等等,当然假设0-63与高速缓存行对齐.

Max*_*kin 80

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

$ getconf LEVEL1_DCACHE_LINESIZE
64
Run Code Online (Sandbox Code Playgroud)

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

$ gcc -DLEVEL1_DCACHE_LINESIZE=`getconf LEVEL1_DCACHE_LINESIZE` ...
Run Code Online (Sandbox Code Playgroud)

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

  • 几年后,但在C代码中你也可以使用sysconf(__ SC_LEVEL1_DCACHE_LINESIZE) (17认同)

Nec*_*lis 34

要了解尺寸,您需要使用处理器的文档查找它,但是没有编程方法.然而,从好的方面来看,大多数缓存行都是标准大小,基于intels标准.在x86缓存行上是64字节,但是,为了防止错误共享,您需要遵循您所针对的处理器的指导原则(intel在其基于netburst的处理器上有一些特殊说明),通常需要为此对齐64个字节(英特尔表示你还应该避免跨越16字节边界).

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

  • C ++ 11添加了alignas,这是指定对齐方式的可移植方式 (3认同)
  • @MetallicPriest:gcc和g ++都支持`__attributes__` (2认同)
  • 您可以通过编程方式获取缓存行大小。检查[此处](http://stackoverflow.com/questions/794632/programmatically-get-the-cache-line-size)。此外,您也不能概括为 x86 上有 64 字节缓存行。仅适用于最近的情况。 (2认同)

Mys*_*ial 9

没有完全可移植的方式来获得缓存行大小.但如果您使用的是x86/64,则可以调用该cpuid指令获取有关缓存的所有信息 - 包括大小,缓存行大小,多少级别等等...

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

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

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

为了对齐mallocs(),所有主流编译器也为此目的使用了对齐的malloc函数.


Fra*_*ini 9

另一个简单的方法就是cat// proc/cpuinfo:

cat/proc/cpuinfo | grep cache_alignment


Met*_*est 8

posix_memalignvalloc可用于将分配的内存与高速缓存行对齐.

  • 我知道这是你自己的问题,但对于未来的读者你可以回答它的两个部分:-) (3认同)
  • 我不认为它是由Posix保证的,但如果linux总是选择页面对齐的地址,我也不会感到惊讶,更别提只是缓存行对齐了.Posix说,如果调用者指定了第一个参数(地址提示),那么它必须是页面对齐的,并且映射本身总是一个整数页面.这是强烈的暗示,没有实际保证任何东西. (3认同)