这可能与 L2 缓存中的冲突有关。
matice1 上的缓存未命中不是问题,因为它们是按顺序访问的。
然而,对于 matice2,如果完整的列适合 L2 (即当您访问 matice2[0, 0]、matice2[1, 0]、matice2[2, 0] ...等时,没有任何内容被驱逐),那么没有问题matice2 的缓存也未命中。
现在要更深入地了解缓存的工作原理,如果变量的字节地址是 X,那么它的缓存行将是 (X >> 6) & (L - 1)。其中 L 是缓存中缓存行的总数。 L 始终是 2 的幂。
这 6 个事实是因为 2^6 == 64 字节是缓存行的标准大小。
现在这意味着什么?这意味着如果我有地址 X 和地址 Y 并且
(X >> 6) - (Y >> 6) 可以被 L(即 2 的某个大幂)整除,它们将存储在同一个缓存行中。
现在回到你的问题 2048 年和 2049 年有什么区别,
当 2048 是你的尺寸时:
如果您采用 &matice2[x, k] 和 &matice2[y, k] 差值 (&matice2[x, k] >> 6) - (&matice2[y,k] >> 6) 将被 2048 * 4 整除(大小的浮动)。所以是2的大幂。
因此,根据 L2 的大小,您将遇到很多缓存行冲突,并且仅利用 L2 的一小部分来存储列,因此您实际上无法在缓存中存储完整的列,因此您的性能会很差。
当大小为 2049 时,差异为 2049 * 4,它不是 2 的幂,因此您的冲突会更少,并且您的列将安全地适合您的缓存。
现在为了检验这个理论,你可以做几件事:
像这样 matice2 [razmor, 4096] 分配您的数组 matice2 数组,并以 razmor = 1024、1025 或任何大小运行,您应该会看到与之前相比非常糟糕的性能。这是因为您强制对齐所有列以使其相互冲突。
然后尝试 matice2 [razmor, 4097] 并以任何大小运行它,您应该会看到更好的性能。