在x86指令中写入非阻塞内存?

时间:2013-11-23 18:24:33

标签: c x86 sse hpc

我正在编写一些高度优化的代码,这里有一件事让我误解了很长一段时间,我有一个像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的非阻塞内存写入指令?或者我可以用这个记忆写的其他一些技巧?请不要建议改变循环的结构,这太费时间了。

谢谢, 鲍勃

1 个答案:

答案 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]);
        }
    }
}