我正在写一些高度优化的代码,这里有一件事困扰了我很长一段时间,我有一个三重循环的家伙:
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个指针组成的结构,每个指针指向一个大数组。这段代码最初是以array of struct(AoS)模式编写的,我手动重写了整个过程以使用array的struct,这样就可以使用SSE来加快速度。但由于代码的原始结构,上面的代码必须以不友好的方式将结果写入正确的缓存位置,如果我注释掉这一行,我整个程序的运行时间可以减少40%以上。我只是想知道是否有任何用于x86的非阻塞内存写指令可以利用?或者其他一些我可以玩的记忆写的把戏?请不要建议改变循环的结构,这太费时了。
谢谢,
鲍勃
最佳答案
请参阅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]);
}
}
}