在二维数组上缓存不友好的循环比缓存友好的循环更快
Cache unfriendly loop over 2d-array faster than cache friendly loop
为什么使用 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 是double[N][N]数组)
版本 2 不应该更快,因为在循环中使用 [j][k] 对 mat2 进行索引是缓存友好的(当将 mat2[j][k] 从 ram 加载到缓存 mat2[j][k 时+1], mat2[j][k+2],... 也将被加载,因为它们在同一条缓存线上))?
(如果我关闭编译器优化(使用:"#pragma optimize( "", off )")版本 2 比版本 1 快,但代码运行速度慢很多(显然))。
编辑:
性能:(使用 windows.h ==> QueryPerformanceCounter 测量的时间)
使用编译器优化:版本 1:~493 毫秒;版本 2:954 毫秒
没有编译器优化:版本 1:~3868 毫秒;版本 2:~2266 毫秒
使用优化,对于第一个版本,编译器显然可以将内部两个循环重新排序为:
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]
因为它在进行上述优化后,在内循环中没有改变。
为什么使用 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 是double[N][N]数组)
版本 2 不应该更快,因为在循环中使用 [j][k] 对 mat2 进行索引是缓存友好的(当将 mat2[j][k] 从 ram 加载到缓存 mat2[j][k 时+1], mat2[j][k+2],... 也将被加载,因为它们在同一条缓存线上))?
(如果我关闭编译器优化(使用:"#pragma optimize( "", off )")版本 2 比版本 1 快,但代码运行速度慢很多(显然))。
编辑:
性能:(使用 windows.h ==> QueryPerformanceCounter 测量的时间)
使用编译器优化:版本 1:~493 毫秒;版本 2:954 毫秒 没有编译器优化:版本 1:~3868 毫秒;版本 2:~2266 毫秒
使用优化,对于第一个版本,编译器显然可以将内部两个循环重新排序为:
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]
因为它在进行上述优化后,在内循环中没有改变。