缓存行对齐(需要澄清文章)

10

我最近在我的应用程序中遇到了一个我认为是虚假共享的问题,我查询了Sutter的文章关于如何将我的数据对齐到缓存行。他建议使用以下C++代码:

// C++ (using C++0x alignment syntax)
template<typename T>
struct cache_line_storage {
   [[ align(CACHE_LINE_SIZE) ]] T data;
   char pad[ CACHE_LINE_SIZE > sizeof(T)
        ? CACHE_LINE_SIZE - sizeof(T)
        : 1 ];
};

我可以理解当CACHE_LINE_SIZE > sizeof(T)时的情况,结构体cache_line_storage会占据一个完整的缓存行内存。然而,当sizeof(T)大于一个缓存行时,我认为我们应该通过填充数据来使结果结构体的大小是缓存行大小的整数倍,即填充CACHE_LINE_SIZE - T % CACHE_LINE_SIZE字节。那么,我的理解有什么问题吗?为什么填充1个字节就足够了?
3个回答

7

数组大小不能为0,因此需要1才能编译通过。然而,当前的草案规范表明这种填充是不必要的;编译器必须填充到结构体的对齐方式。

还要注意,如果CACHE_LINE_SIZE小于alignof(T),则此代码无效。为了解决这个问题,你应该使用[[align(CACHE_LINE_SIZE), align(T)]],这将确保永远不会选择更小的对齐方式。


+1。虽然在实际操作中,我不知道任何一个结构体对齐的大小可以超过缓存行的大小,毕竟类型对齐约束通常来自于缓存行约束。 - Bahbar
1
在您的建议中,对齐应用于结构体本身还是结构体的第一个元素? - Heath Hunnicutt
1
但是关于伪共享本身的机制...为了防止它,即使sizeof(T)>CACHE_LINE_SIZET是否应该对齐到缓存行大小的整数倍?或者这不是必要的吗? - int3
@splicer:对齐方式始终是2的幂次方。因此,如果align(T)>CACHE_LINE_SIZE,则它是CACHE_LINE_SIZE的倍数。 - Bahbar
1
哦...这让我生气到要去验证规范http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf了。在3.1.5中,我们有这样的描述:“对齐方式从较弱到更强或更严格的顺序排列。更严格的对齐方式具有更大的对齐值。满足对齐要求的地址也满足任何较弱但有效的对齐要求。”那最后一句意味着对齐方式是彼此的倍数。你仍然可以想象非2的幂次方对齐方式,但倍数关系仍然存在。2和3不能同时成为同一实现上的有效对齐方式。 - Bahbar
显示剩余3条评论

3

想象一下

#define CACHE_LINE_SIZE 32
sizeof(T) == 48

现在,考虑一下如何使用[[ align(CACHE_LINE_SIZE) ]]。例如:
[[ align(32) ]] Foo foo;

这将强制使某些 nsizeof(Foo) == 32n。也就是说,如果需要的话,align() 会为您填充空间,以便像 Foo foo[10]; 这样的数组中的每个 foo[i] 都按照所需对齐。

因此,在我们的情况下,sizeof(T) == 48,这意味着 sizeof(cache_line_storage<T>) == 64

因此,对齐方式为您提供了所需的填充空间。

然而,这是模板中的一个“错误”。考虑以下情况:

#define CACHE_LINE_SIZE 32
sizeof(T) == 32

这里我们最终得到了一个char pad [1];。这意味着sizeof(cache_line_storage<T>) == 64。这可能不是您想要的!我认为需要在模板上做一些修改:
template <typename T, int padding>
struct pad_or_not
{
   T data;
   char pad[padding];
};

// specialize the 0 case
// As it is late, I am SURE I've got the specialization syntax wrong...
template <typename T, int>
struct pad_or_not<0>
{
   T data;
};

template<typename T>
struct cache_line_storage {
   [[ align(CACHE_LINE_SIZE) ]] pad_or_not<T, (sizeof(T) > CACHE_LINE_SIZE ? 0 : CACHE_LINE_SIZE - sizeof(T) ) > data;
};

或者类似于这样的东西。

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接