有没有一种更快的方法可以在SIMD上乘以2(不使用多重应用程序)
Is there a faster way to multiply by 2 on SIMD (without using muliplication)?
旧浮点的一个技巧是从不乘以2,而是将操作数与自身相加,如2*A=A+A。旧技巧是否仍然适用于SSE/SSE2/SSSE3/NEON/。。。指令集等等?我的操作数是一个向量(比如说,4个浮点,我想乘以2)。乘以3,4…怎么样。。。?
我仍在努力寻找一个例子,说明这会在哪里产生影响。我的直觉是,如果延迟是一个问题,那么在某些情况下x+x
会更好,但如果延迟不是一个问题并且只影响吞吐量,那么情况可能会更糟。但首先让我们讨论一些硬件。
让我坚持使用英特尔x86处理器,因为这是我最了解的。让我们考虑以下几代硬件:Core2/Nehalem、SandyBridge/IvyBridge和Haswell/Broadwell。
SIMD浮点指针算术运算的延迟和吞吐量:
- 添加的延迟为3
- 除了Broadwell,乘法的延迟是5
- 在Broadwell上,乘法的延迟为3
- 添加的吞吐量为1
- 除了Haswell和Broadwell,乘法运算的吞吐量是1
- 在Haswell和Broadwell上,multipliccatin的吞吐量为2
- 在没有FMA的情况下,加法和乘法的吞吐量为2
- FMA的延迟为5
- FMA的吞吐量为2。这相当于4的加法和乘法吞吐量
这是我实际用于生成因子为2的Mandelbrot集的一个例子。在主循环中,两行最关键的代码是:
x = x*x - y*y + x0;
y = 2*xtemp*y + y0;
这里所有的变量都是SIMD(SSE或AVX)寄存器,所以我一次处理多个像素(4个带有SSE,8个带有AVX用于单个浮点)。为此,我使用了一个围绕内部函数的SIMD类。对于y
,我可以做
y = xtemp*y + xtemp*y + y0
FMA呢?
y = fma(2*xtemp, y, y0)
或
y = xtemp*y + fma(xtemp, y, y0);
有许多变化可以尝试。我没有试过y=xtemp*y + xtemp*y + y0
,但我认为它会更糟。顺便说一句,事实证明,到目前为止,我在Haswell系统上实现它的方式并没有多大帮助。使用FMA,我的帧速率只增加了15%左右,而当我从使用SSE的4像素增加到使用AVX的8像素时,帧速率几乎翻了一番。
编辑:以下是一些我认为会有所不同的案例,但要么它们在实践中没有,要么它们做起来没有意义。
考虑这种情况
for(int i=0; i<n; i++) y[i] = 2*x[i];
在这种情况下,延迟无关紧要,吞吐量很重要。在Haswell和Broadwell上,乘法的吞吐量是加法的两倍,因此在这种情况下,执行x+x
可能会更糟,但由于Haswell/Broadwell每个时钟周期只能写入32字节,因此没有什么区别。
以下是使用x+x
似乎更好的情况。
for(int i=0; i<n; i++) prod = prod * (2*x[i]);
相反,你可以这样做:
for(int i=0; i<n; i++) prod = prod * (x[i]+x[i]);
在这两种情况下都没有区别,因为它们由prod
的乘法的延迟所支配。然而,如果你将循环展开足够的次数,这样延迟就无关紧要了,那么第二种情况通常会更好,因为所有处理器至少在每个时钟周期都可以进行加法和乘法运算尽管Haswell和Broadwell每个时钟周期可以进行两次乘法运算,但他们也可以使用FMA在每个时钟周期进行两次加法运算和乘法运算,因此即使在他们身上也会更好。
然而,在这种情况下,明智的做法是
for(int i=0; i<n; i++) prod *= x[i];
prod *= pow(2,n);
因此没有必要用x+x
代替2*x
。
编译器编写者非常聪明。对于浮点数x,2.0*x和x+x是绝对相同的。因此,编译器完全可以用x+x替换2.0*x,反之亦然,这取决于速度更快。
这可能很复杂。添加通常更快。但考虑一个处理器,它可以在每个循环中进行一次乘法和一次加法。然后,您需要将2*x和2*y替换为2*x和y+y。如果你有一个运算2*x和y+z,那么你不想用x+x代替2*x,因为你有两个加法,只能在两个循环中进行。然后是具有融合乘加的处理器,它可以在一次运算中计算a*b+c。所以你不想把2*x+y改成(x+x)+y。
最好把它留给编译器。
- 试图在visual studio上用C++创建一个桌面应用程序
- FFmpeg:制作一个应用程序比直接使用ffmepg更好吗
- 在C应用程序中运行C++(带有STL)函数
- 使用VerQueryValue检索应用程序的文件描述
- Qt C++静态thread_local QNetworkAccessManager是线程应用程序的好选择吗
- 使用调试/崩溃报告将应用程序部署到客户端
- C++控制台应用程序阻止退出
- 码头化的C++应用程序是否向后兼容早期的内核版本
- 将应用程序从32位移植到64位时出现问题
- 如何改变c++应用程序的视觉效果
- WM_CTLCOLORSTATIC从未在WIN32应用程序中触发
- PC中的程序和PHONE中的本机描述应用程序之间的数据连接
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- 示例外壳应用程序显示的 V8 "segmentation fault (core dumped)"错误
- phytec phyBOARD iMX-6在从闪存而不是SD卡运行qt5 opengles应用程序时表现不佳(FPS减半
- 为什么导入Mixed native/CLR lib.dll的本机C++应用程序没有在Mixed lib.dll中的外部变
- 如何从Windows应用程序输出到标准?
- C++应用程序 MySQL odbc 数据库连接错误:在引发"otl_tmpl_exception<>"实例后终止调用
- 如何在 64 位 vb.net Windows 应用程序中引用 32 位 dll
- 有没有一种更快的方法可以在SIMD上乘以2(不使用多重应用程序)