如何更快地制作以下代码

时间:2010-12-15 12:58:28

标签: c optimization sse simd sse2

int u1, u2;  
unsigned long elm1[20], _mulpre[16][20], res1[40], res2[40]; 64 bits long     
res1, res2 initialized to zero.  

l = 60;  
while (l)  
{  
    for (i = 0; i < 20; i += 2)  
    {  
        u1 = (elm1[i] >> l) & 15;  
        u2 = (elm1[i + 1] >> l) & 15;

        for (k = 0; k < 20; k += 2)  
        {  
            simda = _mm_load_si128 ((__m128i *) &_mulpre[u1][k]);  
            simdb = _mm_load_si128 ((__m128i *) &res1[i + k]);  
            simdb = _mm_xor_si128  (simda, simdb);  
            _mm_store_si128 ((__m128i *)&res1[i + k], simdb);  

            simda = _mm_load_si128 ((__m128i *)&_mulpre[u2][k]);  
            simdb = _mm_load_si128 ((__m128i *)&res2[i + k]);  
            simdb = _mm_xor_si128  (simda, simdb);  
            _mm_store_si128 ((__m128i *)&res2[i + k], simdb);  
        } 
    }
    l -= 4;
    All res1, res2 values are left shifted by 4 bits.  
}

在我的程序中多次调用上面提到的代码(分析器显示98%)。

编辑:在内部循环中,对于相同的(i + k)值,res1 [i + k]值被多次加载。我在while循环中尝试了这个,我将所有res1值加载到simd寄存器(数组)中,并使用最里面for循环内的数组元素来更新数组元素。完成两个for循环后,我将数组值存储回res1,re2。但是计算时间随之增加。知道我哪里错了吗?这个想法似乎是正确的

欢迎任何提高速度的建议。

4 个答案:

答案 0 :(得分:2)

不幸的是,编译器可能已经完成了最明显的优化:

  • 您可以拉出内循环的&_mulpre[u1]&mulpre[u2]
  • 你可以拉出&res1[i]我们的内循环。
  • 对两个内部操作使用不同的变量并重新排序它们可能允许更好的流水线操作。

可能交换外部循环将改善elm1上的缓存局部性。

答案 1 :(得分:0)

嗯,你总是可以少打电话: - )

总投入&amp;输出数据看起来相对较小,取决于您的设计和预期输入,只是缓存计算或进行延迟评估而不是预先进行可能是可行的。

答案 2 :(得分:0)

你可以用这样的例程做很少的事情,因为加载和存储将是主导因素(对于单个计算指令,你正在做2个加载+ 1个存储= 4个总线周期)。

答案 3 :(得分:0)

l = 60;  
while (l)  
{  
    for (i = 0; i < 20; i += 2)  
    {  
        u1 = (elm1[i] >> l) & 15;  
        u2 = (elm1[i + 1] >> l) & 15;

        for (k = 0; k < 20; k += 2)  
        {  
            _mm_stream_si128 ((__m128i *)&res1[i + k],
                    _mm_xor_si128  (
                                    _mm_load_si128 ((__m128i *) &_mulpre[u1][k]),
                                    _mm_load_si128 ((__m128i *) &res1[i + k]
                                   ));  

            mm_stream_si128 ((__m128i *)&res2[i + k],    
                    _mm_xor_si128  (
                                    _mm_load_si128 ((__m128i *)&_mulpre[u2][k]), 
                                    _mm_load_si128 ((__m128i *)&res2[i + k])
                                   ));  
        } 
    }
    l -= 4;
    All res1, res2 values are left shifted by 4 bits.  
}
  1. 请记住您使用的是内在的,使用较少_ 128mi / _mm128值会加快您的程序。
  2. 尝试_mm_stream_si128(),它可能会加快存储过程。
  3. 尝试预取