每个内存地址基于地址的模运算“映射”到它们自己在 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] 中的元素给出相同的缓存行模结果?或者,这实际上会提高性能吗,因为只需加载一个高速缓存行即可获得两个数据位置?
有人能举出上面的例子来说明由于缓存映射导致的性能变化,包括数组的对齐方式会对此产生怎样的影响吗?
(我的问题的原因是我试图了解何时由于数据对齐/地址映射到同一缓存行而导致性能问题发生,这导致其中一条数据未存储在缓存中)
注意:我可能混淆了术语缓存“行”和“设置”- 请随时更正。
最佳答案
现在您的代码没有多大意义,因为您没有为数组分配任何内存。指针只是 2 个未初始化的变量,位于堆栈中并且指向任何内容。此外,指向 int* 的指针实际上并没有 size()
函数。
假设你解决了所有问题,如果你分配了,你可以决定是否连续分配数据。您可以为一个指针分配 2*N 个整数,并让另一个指向该区域的中间。
这里的主要考虑因素是——如果数组足够小以至于不会环绕您想要的缓存级别,让它们连续映射将避免在它们之间共享相同的缓存集。这可能会提高性能,因为出于 HW 的考虑,同时访问相同的集合通常不是最佳的。
抖动的考虑(两个数组是否会将彼此的行抛出缓存)实际上并不是问题,因为当今大多数缓存都享有某种程度的关联性——这意味着数组可以映射到相同的集合但存在于不同的缓存方式。如果数组太大并且超过了总路径数,那么这意味着它们的地址范围多次环绕缓存集映射,在这种情况下它如何对齐并不重要,你仍然会发生冲突与其他数组的一些行
例如,如果您在缓存中有 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]
但如上所述 - 同一迭代中的访问将转到不同的集合,这可能有一些好处。
关于c++ - 由于数据的物理布局导致缓存性能下降,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23718742/