【问题标题】:Cache performance degradation due to physical layout of data由于数据的物理布局导致缓存性能下降
【发布时间】:2014-05-18 05:06:27
【问题描述】:

基于地址的模运算,每个内存地址“映射”到它们自己在 CPU 缓存中的缓存集。

有没有办法访问两个大小相同的数组,像这样:

int* array1;  //How does the alignment affect the possibility of cache collisions?
int* array2;

for(int i=0; i<array1.size(); i++){
    x = array1[i] * array2[i];   //Can these ever not be loaded in cache at same time?
}

会导致性能下降,因为 array1[i] 和 array2[i] 处的元素给出相同的高速缓存行模结果?或者,这实际上是否会提高性能,因为只需加​​载一个缓存行即可获得两个数据位置?

有人能举个例子说明由于缓存映射导致的性能变化,包括数组的对齐方式会如何影响这一点吗?

(我提出问题的原因是我试图了解何时由于数据对齐/地址映射到同一缓存行而发生性能问题,这会导致其中一条数据未存储在缓存中)

注意:我可能混淆了缓存“行”和“设置”这两个术语 - 请随时更正。

【问题讨论】:

  • 你认为存在两个不能同时缓存的地址a吗?这不是真的。
  • @n.m.从技术上讲,对于 直接映射 缓存,只有两个地址会产生冲突未命中。直接映射的缓存现在即使在嵌入式系统中也很少见,但过去经常使用直接映射。
  • @PaulA.Clayton 谢谢,不知道。
  • 如果 array1 和 array2 可以放在同一个缓存行中,那么是的,应该会提高性能,让您的逻辑可以直接访问它们的元素(而不是将它们用作指针并加载在堆因此会污染您的缓存)

标签: c++ performance optimization cpu-architecture cpu-cache


【解决方案1】:

现在您的代码没有多大意义,因为您没有为数组分配任何内存。指针只是位于堆栈上的 2 个未初始化的变量,并且没有指向任何内容。此外,指向 int* 的指针实际上并没有 size() 函数。

假设您解决了所有问题,如果您进行分配,您可以决定是否连续分配数据。您可以为一个指针分配 2*N 个整数,并将另一个指向该区域的中间。

这里的主要考虑因素是 - 如果数组足够小以至于无法环绕所需的缓存级别,则将它们连续映射将避免在它们之间共享相同的缓存集。这可以提高性能,因为由于硬件考虑,对相同集合的同时访问通常不是最佳的。

抖动考虑(两个数组是否会将彼此的行从缓存中抛出)实际上并不是问题,因为当今大多数缓存都具有某种程度的关联性 - 这意味着数组可以映射到相同的集合但存在于不同的缓存方式。如果数组太大并且超过了总路径数,那么这意味着它们的地址范围会多次环绕缓存集映射,在这种情况下,如何对齐并不重要,你仍然会发生冲突与另一个数组的一些行

例如,如果您在缓存中有 4 个集合和 2 个方式,并尝试使用对齐偏移量映射 2 个 64 个整数的数组,您仍然会填满整个缓存 -

          way0        way1     
set 0   array1[0]   array2[32]
set 1   array1[16]  array2[48]
set 2   array1[32]  array2[0]
set 3   array1[48]  array2[16]

但如上所述 - 同一迭代中的访问将转到不同的集合,这可能有一些好处。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多