INTEL SIMD:为什么就地乘法这么慢?

时间:2018-11-27 20:46:20

标签: c++ sse simd multiplication in-place

我写了一些向量方法,这些方法可以进行简单的原位数学运算或复制,并且对原位变量也有相同的惩罚。

最简单的方法可以归结为以下内容:

void scale(float* dst, const float* src, int count, float factor)
{
    __m128 factorV = _mm_set1_ps(factorV);

    for(int i = 0; i < count; i+= 4)
    {
        __m128 in = _mm_load_ps(src);
        in = _mm_mul_ps(in, factorV);
        _mm_store_ps(dst, in);

        dst += 4;
        src += 4;
    }
}

测试代码:

for(int i = 0; i < 1000000; i++)
{
    scale(alignedMemPtrDst, alignedMemPtrSrc, 256, randomFloatAbsRange1);
}

在测试时,即在SAME缓冲区上重复操作此功能时,我发现如果dst和src相同,则速度相同。如果它们不同,则速度要快70倍左右。主要周期在写作(例如_mm_store_ps)上燃烧

有趣的是,相同的行为并不适用于加法运算,即+ =效果很好,只有* =是一个问题。

-

已在评论中回答。在人工测试中是不正常的。

1 个答案:

答案 0 :(得分:6)

您的factor是否产生不正常的结果?非零但小于FLT_MIN?如果此循环之外存在循环,则该循环会重复就地遍历同一块,数字可能会变得很小,需要缓慢的FP辅助

Turns out, yes是OP的问题)。

重复就地乘法会使数字越来越小,并且系数小于1.0。每次复制并缩放到不同的缓冲区都使用相同的输入。

产生+-InfNaN的结果并不需要花费额外的时间,但是至少在Intel CPU上会逐渐下溢至次正常水平。这是-ffast-math设置DAZ / FTZ的原因之一-下溢时刷新为零。


我想我已经读过AMD并没有使用FP辅助对次常态进行微编码处理,但是Intel确实如此。

fp_assist.any在Intel CPU上有一个性能计数器,用于计算次标准结果何时需要额外的微代码来处理特殊情况。 (我认为这与前端和OoO高管一样具有侵入性。不过,它肯定很慢。)


Why denormalized floats are so much slower than other floats, from hardware architecture viewpoint?

Why is icc generating weird assembly for a simple main?(显示ICC如何在main的开头设置FTZ / DAZ,并使用默认的快速数学设置。)