使用 SIMD 有效地评估大型多项式

问题描述

我有相当大(20-40 度)缓慢收敛(有时)的浮点多项式。我想使用 SIMD(SSE2、AVX1、AVX-512)优化他们的评估。我需要 float-32 和 double-64 解决方案。

系数的值是预先给定的常数,计算 poly at 的 X 的值作为函数参数给出。

重要说明 - 我的函数只有一个输入 X。所以我不能通过同时计算 8-16 Xspoly 来进行垂直优化。这意味着我需要在评估单个 X 时进行一些横向优化。

我创建了 related question 来帮助我计算 SIMD 评估所需的 X(例如 X^1,X^2,...,X^8)的幂。

很明显,SIMD 应该只在多项式次数的某个阈值之后使用,对于非常小的多边形,可以使用基于霍纳(或埃斯特林)的方法like here。此外,应根据多边形度选择 SIMD 宽度(128 或 256 或 512)。

下面我使用一种适用于 SIMD 的修改后的 Horner's Method(乘以 x^8 而不是 x^1)实现了 AVX-256-Float32 变体。归功于@PeterCordes 的快速水平求和 tutorial。点击try-it-online链接代码较大,也有比较和时间测量的参考简单评估:

Try it online!

template <size_t S,size_t I,typename MT = __m256,size_t Cnt>
inline MT Evalpoly8xF32Helper(MT xhi,std::array<float,Cnt> const & A,MT r = _mm256_undefined_ps()) {
    size_t constexpr K = 8;
    if constexpr(I + K >= S)
        r = _mm256_load_ps(&A[I]);
    else {
        #ifdef __FMA__
            r = _mm256_fmadd_ps(r,xhi,_mm256_load_ps(&A[I]));
        #else
            r = _mm256_add_ps(_mm256_mul_ps(r,xhi),_mm256_load_ps(&A[I]));
        #endif
    }
    if constexpr(I < K)
        return r;
    else
        return Evalpoly8xF32Helper<S,I - K>(xhi,A,r);
}

inline float _mm_fast_hsum_ps(__m128 v) {
    __m128 shuf = _mm_movehdup_ps(v);
    __m128 sums = _mm_add_ps(v,shuf);
    shuf        = _mm_movehl_ps(shuf,sums);
    sums        = _mm_add_ss(sums,shuf);
    return        _mm_cvtss_f32(sums);
}

template <size_t S,size_t Cnt>
inline float Evalpoly8xF32(
        float x,Cnt> const & A) {
    auto constexpr K = 8;
    auto const x2 = x * x,x4 = x2 * x2,x8 = x4 * x4,x3 = x2 * x;
    auto const powsx = _mm256_setr_ps(
        1,x,x2,x3,x4,x4 * x,x4 * x2,x4 * x3);
    auto r0 = Evalpoly8xF32Helper<S,(S - 1) / K * K>(
        _mm256_set1_ps(x8),A);
    r0 = _mm256_mul_ps(r0,powsx);
    return _mm_fast_hsum_ps(_mm_add_ps(
        _mm256_castps256_ps128(r0),_mm256_extractf128_ps(r0,1)));
}

正如人们所见,与参考简单实现相比,SIMD 版本提供了相当大的加速。对于 AVX1-256-float32 和度数 32 的情况,它提供了大约 4.5x 倍的加速(对于度数 16,它提供了 1.8x 的加速,这也很好)!显然,即使只是在参考实现中使用 FMA 指令也已经显着提高了计算速度。

我的问题是您是否可以建议一种更快的评估多项式的​​方法,甚至是一些现成的代码或库,或者对我的代码进行任何优化。

最常用的目标 cpuIntel Xeon Gold 6230,它有 AVX-512,所以我需要为它优化代码

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)