缓存行、伪共享和对齐

17
我编写了下面这个简短的C++程序,以重现Herb Sutter所描述的伪共享效应:
假设我们要执行总数为WORKLOAD的整数操作,并希望它们平均分配到一定数量(PARALLEL)的线程中。为了进行此测试,每个线程将从整数数组中递增其自己专用的变量,因此该过程可以理想地并行化。
void thread_func(int* ptr)
{
    for (unsigned i = 0; i < WORKLOAD / PARALLEL; ++i)
    {
        (*ptr)++;
    }
}

int main()
{
    int arr[PARALLEL * PADDING];
    thread threads[PARALLEL];

    for (unsigned i = 0; i < PARALLEL; ++i)
    {
        threads[i] = thread(thread_func, &(arr[i * PADDING]));
    }
    for (auto& th : threads)
    {
        th.join();
    }
    return 0;
}

我认为这个想法很容易理解。如果你设置

#define PADDING 16

每个线程将在单独的缓存行上工作(假设缓存行长度为64字节)。因此,速度提升将呈线性增长,直到PARALLEL > # cores。然而,如果PADDING设置在小于16的任何值,则应该会遇到严重的争用情况,因为至少两个线程现在可能会在同一缓存行上运行,但是这里由内置的硬件互斥锁来保护。我们预计,在这种情况下,我们的加速比不仅会是亚线性的,甚至始终 <1,因为存在隐形的锁定车队。
现在,我的第一个尝试几乎满足了这些期望,但需要避免伪共享的最小PADDING值约为8而不是16。我困惑了大约半个小时,直到我得出了显而易见的结论,即没有保证我的数组在主存储器中准确地对齐到缓存行的开头。实际对齐可能会因包括数组大小在内的许多条件而有所变化。
在这个例子中,我们当然不需要特别对齐数组,因为我们可以将PADDING设置为16,一切都能正常工作。但是有些情况下,某个结构体是否对齐到缓存行可能会产生影响。因此,我添加了一些代码来获取有关我的数组实际对齐方式的信息。
int main()
{
    int arr[PARALLEL * 16];
    thread threads[PARALLEL];
    int offset = 0;

    while (reinterpret_cast<int>(&arr[offset]) % 64) ++offset;
    for (unsigned i = 0; i < PARALLEL; ++i)
    {
        threads[i] = thread(thread_func, &(arr[i * 16 + offset]));
    }
    for (auto& th : threads)
    {
        th.join();
    }
    return 0;
}

虽然这个解决方案在我的情况下很好用,但我不确定它是否是一种普遍的好方法。所以这里有我的问题:

除了我在上面的示例中所做的方式之外,是否有任何常见的方法可以使内存中的对象对齐到缓存行?

(使用g ++ MinGW Win32 x86 v.4.8.1 posix dwarf rev3)


VirtualAlloc?它会分配页面,因此必须对齐。 - Martin James
我很惊讶你能看到任何差异。编译器应该将*ptr保存在寄存器中,从而隐藏虚假共享的惩罚。 - Mysticial
为了学习,我关闭了编译器优化,因此每次必须对ptr进行解引用。 - Rene R.
@DavidRodríguez-dribeas 这是正确的。对齐方式并不重要。但在这种情况下,这可能足以欺骗编译器做一些不那么愚蠢的事情。正如通常情况下一样 - 当关闭优化时,任何事情都可以发生。 - Mysticial
@ReneR。当你有两个线程时,你只需要足够的填充来将另一个线程推到新的缓存行。所以这取决于对齐方式。但是当你有很多线程时,就不重要了。你仍然需要填充>= cachline来将所有线程放在不同的缓存行上。 - Mysticial
显示剩余4条评论
3个回答

17

你应该能够从编译器中请求所需的对齐方式:

alignas(64) int arr[PARALELL * PADDING]; // align the array to a 64 byte line

2
我之前从来没有尝试过这个,因为我认为编译器在 alignas 限定符上的行为可能取决于 ABI。好吧,事实证明它可以在我测试过的每台机器上运行。谢谢。 - Rene R.

4

3

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