我正在编写一些高度优化的代码,这里有一件事让我误解了很长一段时间,我有一个像forrss一样的三重for循环:
for(int ii = 0; ii < ny; ii++){
for(int jj = 0; jj < nx; jj++){
....some serious calculation....
for(int kk = 0; kk < CONSTANT; kk++){
_mm_storeu_ps(&((cells.dir[kk])[ii * nx +jj],result); // Writing result to correct location
}
}
}
单元格只是一个包含9个指针的结构,每个指针指向一个大尺寸数组。代码最初是以struct(AoS)模式的数组编写的,我手动重写了整个使用struct的数组,所以我可以使用SSE来加速它。但由于代码的原始结构,上面的代码必须以缓存不友好的方式将结果写入正确的位置,如果我评论该行,我的整个程序的运行时间可以减少超过40% 。我只是想知道我是否可以利用x86的非阻塞内存写入指令?或者我可以用这个记忆写的其他一些技巧?请不要建议改变循环的结构,这太费时间了。
谢谢, 鲍勃
答案 0 :(得分:1)
请参阅Agner Fog手册optimizing cpp中的第9.11节显式缓存控制。请特别查看第99页的示例9.6b(下面发布),其中显示了如何在不使用_mm_stream_pi
内在函数读取缓存行的情况下进行写入。我自己还没试过,但值得研究。当矩阵大小是临界步幅的倍数时,这会有所帮助。但是,更好的解决方案可能是更改代码并使用循环切片(参见示例9.5b),但您说您不想更改循环的结构,因此使用_mm_stream_ps
可能是最佳选择。
// From Agner Fog's manual optimizing cpp on page 99
// Example 9.6b
#include "xmmintrin.h" // header for intrinsic functions
// This function stores a double without loading a cache line:
static inline void StoreNTD(double * dest, double const & source) {
_mm_stream_pi((__m64*)dest, *(__m64*)&source); // MOVNTQ
_mm_empty(); // EMMS
}
const int SIZE = 512; // number of rows and columns in matrix
// function to transpose and copy matrix
void TransposeCopy(double a[SIZE][SIZE], double b[SIZE][SIZE]) {
int r, c;
for (r = 0; r < SIZE; r++) {
for (c = 0; c < SIZE; c++) {
StoreNTD(&a[c][r], b[r][c]);
}
}
}