2013-11-23 18 views
1

我写了一些高度优化的代码,这里是一两件事,已窃听我相当长一段时间,我有一个三重for循环一样研究员:在x86指令中写入非阻塞存储器?

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)模式的数组编写的,我手动重写了整个事物以使用数组的结构,因此我可以使用SSE加速它。但由于代码的原始结构,上面的代码必须以缓存不友好的方式将结果写入正确的位置,如果我评论这一行,我整个程序的运行时间可能会减少超过40% 。我只是想知道是否有任何可用于x86的非阻塞式内存写入指令,我可以利用它?或者我可以使用这种内存写入其他一些技巧?请不要建议改变循环的结构,这太耗费时间了。

感谢, 鲍勃

+2

几乎所有现代非嵌入式处理器的写入都是非阻塞的。他们只是被推到队列中,并在后台完成。也就是说,在队列阻塞之前,队列的大小是有限制的。也就是说,也要注意你如何使用缓存线。 – Mysticial

+0

@Mysticial我刚刚发现它更可能是因为''_mm_storeu_ps''非常昂贵,而不是缓存未命中,这会减慢我的程序。你有什么建议吗? – dorafmon

+0

@dorafmon:你需要将结果放在那些确切的存储位置,或者你打算在以后读回来进行更多的计算?您可以通过将缓存更容易地写入临时缓冲区来提高性能。过去我已经做到了这一点,取得了一些成功。但是,如果这些商店的最终结果需要按照输出数组中的特定顺序进行,那么您可能只是运气不好。 –

回答

1

见9.11 显式高速缓存控制在昂纳雾手册optimizing cpp。特别看看第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]); 
     } 
    } 
}