Saturday, 5 June 2021

How to do vector multiplication using a batch size of 4 in C++?

 https://blog.csdn.net/fuwenyan/article/details/77742766

 

本博记录为卤煮理解,如有疏漏,请指正。转载请注明出处。

卤煮:非文艺小燕儿

本博地址:利用SSE计算向量点乘simd_dot


所谓SSE(Streaming SIMD Extensions),也就是单指令多数据流的扩展。所谓单指令多数据流呢,简单理解就是多个数据流同时处理一条指令。

举个栗子:

一个水箱中的水,底部开1个洞放水,就是单指令单数据流。底部同时开多个相同大小的洞放水,就是单指令多数据流。

多个洞放水当然会比1个洞放得快啦,也就是同样的指令,多数据流速度就快呀。



对于SSE,其实就是处理器中专门开辟了多个128位的寄存器。对于单精度浮点数,占用32bit,那么1个128bit的SSE寄存器,就可以存放4个单精度浮点数。对于单精度浮点数的运算指令,其实就相当于开了4个洞。比如,两个128位的SSE寄存器中存放的数据进行乘法运算,那么一次性就能得到4组运算结果。



大概就是这么个意思。接下来就对采用SSE优化的向量点乘进行详细注释说明。

输入x和y都是长度为len的向量。我们要求x.*y,并将结果返回。
————————————————
版权声明:本文为CSDN博主「非文艺小燕儿_Vivien」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fuwenyan/article/details/77742766


============

float simd_dot(const float* x, const float* y, const long& len) {
    float inner_prod = 0.0f;
    __m128 X, Y; //声明两个存放在SSE的128位专用寄存器的变量
    __m128 acc = _mm_setzero_ps(); // 声明一个存放在SSE的128位专用寄存器的变量,用来存放X+Y的结果,初始值为0
    float temp[4];//存放中间变量的参数
 
    long i;
    for (i = 0; i + 4 < len; i += 4) {//128位专用寄存器,一次性可以处理4组32位变量的运算
        X = _mm_loadu_ps(x + i); // 将x加载到X(由于128位可以存放四个32位数据,所以默认一次加载连续的4个参数)
        Y = _mm_loadu_ps(y + i);//同上
        acc = _mm_add_ps(acc, _mm_mul_ps(X, Y));//x*y,每轮的x1*y1求和,x2*y2求和,x3*y3求和,x4*y4求和,最终产生的四个和,放在acc的128位寄存器中。
    }
    _mm_storeu_ps(&temp[0], acc); // 将acc中的4个32位的数据加载进内存
    inner_prod = temp[0] + temp[1] + temp[2] + temp[3];//点乘求和
 
    // 刚才只是处理了前4的倍数个元素的点乘,如果len不是4的倍数,那么还有个小尾巴要处理一下
    for (; i < len; ++i) {
        inner_prod += x[i] * y[i];//继续累加小尾巴的乘积
    }
    return inner_prod;//大功告成
}
  

No comments:

Post a Comment