gpt4 book ai didi

c++ - 在 Intel CPU 上缓存对齐的内存分配

转载 作者:搜寻专家 更新时间:2023-10-31 02:13:45 25 4
gpt4 key购买 nike

最近我遇到了 Intel TBB 可扩展分配器的问题。基本使用模式如下,

  1. 几个大小为 N * sizeof(double) 的 vector 分配
  2. 生成一个随机整数 M这样 M >= N / 2 && M <= N .
  3. 第一个M访问每个 vector 的元素。
  4. 重复第 2 步 1000 次。

我设置了M是随机的,因为我不想对固定长度的性能进行基准测试。相反,我想在一定长度的 vector 上获得平均性能。

对于N的不同值,程序性能差异很大.这并不少见,因为我正在测试的功能旨在优先考虑大型 N 的性能。 .但是,当我尝试对性能和 N 之间的关系进行基准测试时,我发现在某个时候,当 N 时有两倍的差异。从 1016 增加至 1017 .

我的第一直觉是 N = 1016 的性能下降与较小的 vector 大小无关,而是与缓存有关。很可能存在虚假共享。品尝make下的函数使用了SIMD指令但没有栈内存。它从第一个 vector 中读取一个 32 字节的元素,并在计算后将 32 字节写入第二个(和第三个) vector 。如果发生错误共享,可能会丢失几十个周期,这正是我观察到的性能损失。一些分析证实了这一点。

最初我将每个 vector 与 32 字节边界对齐,用于 AVX 指令。为了解决这个问题,我将 vector 与 64 字节边界对齐。但是,我仍然观察到相同的性能损失。按 128 字节对齐解决问题。

我又做了一些挖掘。英特尔 TBB 有一个 cache_aligned_allocator .在其源代码中,内存也按 128 字节对齐。

这是我不明白的。如果我没记错的话,现代 x86 CPU 有一个 64 字节的缓存行。 CPUID证实了这一点。以下是在用CPU的基本缓存信息,摘 self 写的一个使用CPUID查特征的小程序,

Vendor    GenuineIntel
Brand Intel(R) Core(TM) i7-4960HQ CPU @ 2.60GHz

====================================================================================================
Deterministic Cache Parameters (EAX = 0x04, ECX = 0x00)
----------------------------------------------------------------------------------------------------
Cache level 1 1 2 3 4
Cache type Data Instruction Unified Unified Unified
Cache size (byte) 32K 32K 256K 6M 128M
Maximum Proc sharing 2 2 2 16 16
Maximum Proc physical 8 8 8 8 8
Coherency line size (byte) 64 64 64 64 64
Physical line partitions 1 1 1 1 16
Ways of associative 8 8 8 12 16
Number of sets 64 64 512 8192 8192
Self initializing Yes Yes Yes Yes Yes
Fully associative No No No No No
Write-back invalidate No No No No No
Cache inclusiveness No No No Yes No
Complex cache indexing No No No Yes Yes
----------------------------------------------------------------------------------------------------

此外,在 Intel TBB 的源代码中,128 字节对齐被注释标记为向后兼容。

那么为什么 64 字节对齐在我的情况下不够用?

最佳答案

你被 conflict misses 击中了.当您从 1016 转到 1017 时发生这种情况的原因是您随后开始使用关联列表中的最后一个缓存行。

您的缓存是 32K 8 路,所以每组都是 4K。您的 64 字节缓存行可以容纳 8 个 double 。但是您的 1017-1024 vector 使用 8K 而不是 4K??? 1024*sizeof(double),那么你使用 N/2->N,所以你使用(除非正好是 N/2)一些相同的低位地址位组合为每个 vector 两次。

在您用完所有 L1 缓存之前,您不会遇到冲突命中问题,而您现在接近这样做了。使用 1 个 vector 进行读取,使用 2 个 vector 进行写入,所有长度均为 8K,因此使用 24K,如果您在计算期间使用 8K+ 的额外数据,您将更有可能逐出所选数据。

请注意,您只使用了 vector 的第一部分,但它们之间的冲突从未减少。

当您从 1016 增加到 1017 时,您将能够观察到 L1 缓存未命中的增加。当您超过 1024 倍时,性能损失应该会消失一小段时间,直到您达到 L1 缓存容量未命中。

<在此处成像图表显示在使用所有 8 组时出现尖峰>

来自 Ulrich Drepper 的精彩文章:“Memory part 5: What programmers can doenter image description here

关于c++ - 在 Intel CPU 上缓存对齐的内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40902937/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com