首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何有效地用条件矢量化多项式计算(roofline模型)

如何有效地用条件矢量化多项式计算(roofline模型)
EN

Stack Overflow用户
提问于 2020-08-14 07:31:16
回答 1查看 143关注 0票数 0

我想把一个小次多项式(2-5)应用到一个长度可以在50到3000之间的向量上,并尽可能有效地这样做。例如:我们可以取函数:(1+x^2)^3,当x>3时,0当x<=3时,这样的函数将对双元素的向量执行100 k次。每个向量的大小可以是50到3000之间的任何东西。

一种方法是使用本征: Eigen::ArrayXd v;然后简单地应用函子: v.unaryExpr(& {返回x>3?性病::pow((1+x*x),3.00):0.00;};

在GCC 9和GCC 10的尝试中,我发现这个循环没有被矢量化。我手动地将它矢量化,结果发现增益比我预期的要小得多(1.5倍)。我还用逻辑和指令代替了条件反射,基本上是在x<=3时同时执行分支和对结果进行归零,我认为增益主要来自于没有分支错误预测。

一些考虑,有多个因素在起作用。首先,我的代码中存在原始依赖项(使用本质)。我不知道这对计算有何影响。我用AVX2编写了我的代码,所以我期望得到4倍的收益。我认为这起了一定的作用,但我不能肯定,因为CPU有无序处理。另一个问题是,我不确定我试图编写的循环的性能是否受到内存带宽的限制。

问题如何确定内存带宽或管道危险是否影响此循环的实现?我在哪里可以学到更好地向量化这个循环的技术?在Eigenr、MSVC或Linux中,是否有这方面的好工具?我使用的是AMD CPU,而不是英特尔。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-08-14 08:20:14

您可以用-fno-trapping-math修复GCC错过的优化,这应该是默认的,因为-ftrapping-math甚至不能完全工作。它可以自动矢量化这个选项:https://godbolt.org/z/zfKjjq

代码语言:javascript
复制
#include <stdlib.h>

void foo(double *arr, size_t n) {
    for (size_t i=0 ; i<n ; i++){
        double &tmp = arr[i];
        double sqrp1 = 1.0 + tmp*tmp;
        tmp = tmp>3 ? sqrp1*sqrp1*sqrp1 : 0;
    }
}

它避免了三元的一边的乘数,因为它们可能会引发FP异常,而C++抽象机器则不会。

你会希望用三值外的立方来写它应该让GCC自动矢量化,因为FP的数学运算在源文件中都没有条件。但这实际上没有帮助:https://godbolt.org/z/c7Ms9G GCC的默认-ftrapping-math仍然决定在输入上分支,以避免所有FP计算,可能不会引发C++抽象机器会引发的溢出(到无穷大)异常。如果输入是NaN,则无效。这就是我对-ftrapping-math不起作用的意思。(相关:How to force GCC to assume that a floating-point expression is non-negative?)

Clang也没有问题:当FMA可用时,我建议使用https://godbolt.org/z/KvM9fh来跨语句使用clang -O3 -march=native -ffp-contract=fast

(在这种情况下,-ffp-contract=on就足以在该表达式中收缩1.0 + tmp*tmp,但如果您需要避免使用Kahan求和,则不需要跨语句。clang默认值显然是-ffp-contract=off,给出了不同的mulpd和addpd)

当然,您希望避免使用小整数指数的std::pow。编译器可能不会将其优化为2个乘法,而是调用一个完整的pow函数。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63408407

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档