【发布时间】:2020-06-14 04:44:33
【问题描述】:
当前循环是:
#define N 3000
...
int i, j;
int a[N][N], b[N][N], c[N];
// Fill in b and c with random values
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
a[i][j] = b[i][j] / c[i];
}
}
我的优化版本同时展开了外循环和内循环:
for (int i = 0; i < N; i += 2) {
for (int j = 0; j < N; j += 2) {
a[i][j] = b[i][j] / c[i];
a[i][j + 1] = b[i][j + 1] / c[i];
a[i + 1][j] = b[i + 1][j] / c[i + 1];
a[i + 1][j + 1] = b[i + 1][j + 1] / c[i + 1];
}
}
但是,我的导师说第二个循环没有优化得很好。 c(i) 的指示应该从 j 上的循环中取出。通过更改索引的顺序来优化循环。这样一来,您就可以在内循环中对内存进行一次扫描,而不是进行曲折式的搜索。
我仍然不确定他的意思,因为更改索引的顺序仍然会使循环以之字形遍历。这种情况的正确解决方案应该是什么?
【问题讨论】:
-
这不清楚:“循环是通过改变索引的顺序来优化的。”是对原始代码(问题中显示的第一个代码)还是“我的优化版本”(问题中显示的第二个代码)的评论?看起来代码确实是这样,通常最好在
j上展开循环,而i上的循环并不需要太多关注。 -
展开“i”部分会导致更多的缓存未命中。由于内存布局,最好展开“j”部分。
-
@technosaurus 你的意思是将 j 切换为外循环?
-
不,那会更糟。省略 i+1 展开。它会在每个循环中导致缓存未命中。对于多维数组,内循环应该在最右边的索引之上。展开超过缓存行大小很少显示改进(通常约为 64 字节),但展开至少 16 字节的数据访问有时可以帮助编译器使用 SIMD 指令。
标签: c loops optimization nested-loops