缓存不友好的循环超过2d阵列比缓存友好循环更快

时间:2016-09-24 19:56:29

标签: c++ visual-c++ multidimensional-array cpu-cache

为什么在使用MSVC ++进行编译时版本1比版本2快?

版本1:

for (int i = 0; i < N; ++i)
    for (int j = 0; j < N; ++j)
        for (int k = 0; k < N; ++k)
            res1[i][j] += mat1[i][k] * mat2[k][j];

第2版:

for (int i = 0; i < N; ++i)
    for (int j = 0; j < N; ++j)
        for (int k = 0; k < N; ++k)
            res1[i][j] += mat1[i][k] * mat2[j][k];

(N = 1000; res1,mat1,mat2是双[N] [N]数组)

不应该版本2更快,因为在循环中使用[j] [k]在mat2上进行索引是缓存友好的(当从ram加载mat2 [j] [k]到缓存mat2 [j] [k +1],mat2 [j] [k + 2],...也会加载,因为它们在同一个cachline上))?

(如果我关闭编译器优化(使用:&#34; #pragma optimize(&#34;&#34;,off)&#34;)版本2比版本1快,但代码运行很多慢(显然))。

修改

性能:(使用windows.h ==&gt; QueryPerformanceCounter测量的时间)

使用编译器优化:版本1:~493 ms;版本2:954毫秒 没有编译器优化:版本1:~3888毫秒;版本2:~2266 ms

1 个答案:

答案 0 :(得分:2)

使用优化,对于第一个版本,编译器显然可以将内部两个循环重新排序为:

for (int i = 0; i < N; ++i)
    for (int k = 0; k < N; ++k)
        for (int j = 0; j < N; ++j)
            res1[i][j] += mat1[i][k] * mat2[k][j];       

这将使第一个版本在缓存感知方面与第二个版本类似。

第一个版本快两倍的原因可能是它的第二个术语的缓存:mat1[i][k],因为在进行上述优化之后,它不会在内部循环中发生变化。