最近我遇到了英特尔TBB可扩展分配器的问题。基本使用模式是作为以下,缓存对齐英特尔CPU上的内存分配
- 大小
N * sizeof(double)
的几个矢量分配 - 生成一个随机整数
M
使得M >= N/2 && M <= N
。 - 访问每个向量的第一个
M
元素。 - 重复第2步1000次。
我将M
设为随机,因为我不想将基准性能定为固定长度。相反,我想获得一系列矢量长度的平均性能。
对于不同的值N
,程序性能差别很大。这并不罕见,因为我测试的功能旨在优先考虑大型N
的性能。但是,当我试图对性能和N
之间的关系进行基准测试时,我发现在某个点上,当N
从1016
增加到1017
时,会有两倍的差异。
我的第一个直觉是N = 1016
的性能变差与较小的向量大小无关,而是它有一定的缓存。很有可能存在虚假分享。品尝下的功能使用SIMD指令,但不使用堆栈内存。它从第一个向量中读取一个32字节的元素,并在计算之后,它将第二个(和第三个)向量写入32个字节。如果发生虚假共享,可能会丢失几十个周期,这正是我观察到的性能损失。一些分析证实了这一点。
本来我将每个向量与32字节边界对齐,用于AVX指令。为了解决这个问题,我将矢量与64字节的边界对齐。但是,我仍然观察到相同的性能损失。通过128字节对齐解决问题。
我做了一些更多的挖掘。英特尔TBB有一个cache_aligned_allocator
。在它的源代码中,内存也由128字节对齐。
这是我不明白。如果我没有弄错,现代的x86 CPU有一个64字节的缓存行。 CPUID
证实了这一点。以下是正在使用的CPU,从我写使用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
----------------------------------------------------------------------------------------------------
此外,英特尔TBB的源代码,128个字节对齐的特点是评论这是为了向后兼容。
那么为什么在我的情况下64字节对齐不够?
感谢您的详细说明。这是我知道的,尽管解释得更清楚。然而,如果不增加分配的内存大小,是否有办法避免这种冲突呢?我的印象是,通过对齐63字节的边界足以避免两个向量在大多数情况下共享相同的缓存行。相反,我观察到需要128字节的对齐方式 –
感谢您的图表和链接。我会先阅读一下。 –
对齐并不重要,因为它是set-associativesnes,这是问题在这里,意思是向量使用的总内存。 – Surt