如何使用条件有效地矢量化多项式计算屋顶线模型

问题描述

我想对长度可以在50到3000之间的向量应用小次数(2-5)的多项式,并尽可能高效地执行此操作。 示例:例如,我们可以采用以下函数:(1 + x ^ 2)^ 3,当x> 3时为0,当x

一个想法是使用Eigen: Eigen :: ArrayXd v; 然后只需应用一个仿函数: v.unaryExpr([&](double x){return x> 3?std :: pow((1 + x * x),3.00):0.00;});

在尝试使用GCC 9和GCC 10时,我看到此循环没有被向量化。我确实手动对其进行了矢量化处理,只是发现增益比我预期的要小得多(1.5倍)。我还用逻辑AND指令替换了条件,基本上执行了两个分支,并且在x

一些注意事项 有多种因素在起作用。首先,我的代码中存在RAW依赖项(使用内部函数)。我不确定这如何影响计算。我用AVX2编写了代码,因此我期望获得4倍的收益。我认为这起了一定作用,但是我不确定,因为CPU的处理顺序混乱。另一个问题是我不确定我要编写的循环的性能是否受内存带宽的约束。

问题 如何确定内存带宽或流水线危害是否正在影响此循环的实现?在哪里可以学习更好地向量化此循环的技术?在Eigenr MSVC或Linux中是否有好的工具?我使用的是AMD CPU,而不是Intel。

解决方法

您可以使用-fno-trapping-math来解决GCC遗漏的优化问题,因为-ftrapping-math甚至无法完全发挥作用,因此这应该是默认设置。可以使用以下选项自动矢量化:https://godbolt.org/z/zfKjjq

#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;
    }
}

避免在三元数的一侧进行乘法运算,因为它们可能会引发C ++抽象机不会出现的FP异常。

您希望使用三元数之外的多维数据集进行编写应该使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?


C语也没有问题:https://godbolt.org/z/KvM9fh 我建议在FMA可用时使用clang -O3 -march=native -ffp-contract=fast来获取语句之间的FMA。

(在这种情况下, -ffp-contract=on足以在一个表达式内收缩1.0 + tmp*tmp,但如果需要避免例如对Kahan求和,则不能跨语句。在clang中,默认值是{{ 1}},分别给出mulpd和addpd)


当然,您要避免使用小整数指数的-ffp-contract=off。编译器可能不会将其优化为仅2个乘法,而是调用完整的std::pow函数。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...