【问题标题】:SSE vectorization of math 'pow' function gcc数学“pow”函数 gcc 的 SSE 矢量化
【发布时间】:2011-10-18 14:08:47
【问题描述】:

我试图对包含数学库中“pow”函数使用的循环进行矢量化。我知道英特尔编译器支持对 sse 指令使用“pow”——但我似乎无法让它与 gcc 一起运行(我认为)。这是我正在处理的情况:

int main(){
        int i=0;
        float a[256],
        b[256];

        float x= 2.3;


        for  (i =0 ; i<256; i++){
                a[i]=1.5;
        }

        for (i=0; i<256; i++){
                b[i]=pow(a[i],x);
        }

        for (i=0; i<256; i++){
                b[i]=a[i]*a[i];
        }
    return 0;

}

我正在编译以下内容:

gcc -O3 -Wall -ftree-vectorize -msse2 -ftree-vectorizer-verbose=5 code.c -o runthis

这是在 os X 10.5.8 上使用 gcc 4.2 版(我也使用 4.5 并且无法判断它是否已经矢量化任何东西 - 因为它根本没有输出任何东西)。似乎没有一个循环矢量化 - 是否存在对齐问题或我需要使用限制的其他问题?如果我将其中一个循环编写为函数,我会得到更详细的输出(代码):

void pow2(float *a, float * b, int n) {
        int i;
        for (i=0; i<n; i++){
                b[i]=a[i]*a[i];
        }
}

输出(使用 7 级详细输出):

note: not vectorized: can't determine dependence between *D.2878_13 and *D.2877_8
bad data dependence.

我查看了gcc auto-vectorization 页面,但这并没有太大帮助。如果在 gcc 版本中无法使用 pow,我在哪里可以找到资源来执行 pow - 等效函数(我主要处理整数幂)。

编辑 所以我只是在挖掘其他来源 - 它是如何矢量化这个的?!:

void array_op(double * d,int len,double value,void (*f)(double*,double*) ) { 
    for ( int i = 0; i < len; i++ ){
        f(&d[i],&value);
    }
};

相关的gcc输出:

note: Profitability threshold is 3 loop iterations.

note: LOOP VECTORIZED.

现在我不知所措了——“d”和“value”被 gcc 不知道的函数修改了——奇怪吗?也许我需要更彻底地测试这部分,以确保矢量化部分的结果是正确的。仍在寻找矢量化数学库 - 为什么没有任何开源的?

【问题讨论】:

  • main 优化为return 0 是正常的:main 之外的任何东西都无法观察到结果,因此完全优化循环不会改变程序行为的任何内容。数组是具有自动存储功能的局部变量,因此不会产生副作用,例如调用 malloc/free 以供编译器保留。

标签: c optimization loops sse vectorization


【解决方案1】:

在编写输出之前使用__restrict 或使用输入(分配给本地变量)应该会有所帮助。

现在,编译器无法向量化,因为 a 可能别名为 b,因此并行执行 4 次乘法并写回 4 个值可能不正确。

(请注意,__restrict 不会保证编译器会向量化,但现在可以说这么多,它肯定 不能)。

【讨论】:

  • 即使这不能解决这个问题,也值得花时间了解这里推荐的内容以及为什么,因为除非你这样做,否则你永远无法猜到编译器可以优化什么,不能优化什么。
  • 这当然适用于简单的 b=a*a,但是 pow 函数呢?你能指点我一个资源吗?我不想(/有时间)自己写——但如果我必须这样做,那也不是最糟糕的事情。
  • 类似this?
  • @Damon 禁用严格的别名规则不仅会导致矢量化问题,而且肯定会导致其他优化问题吗?虽然我认为可以相应地更改代码以获得一些小的性能影响。
  • @Voo:禁用严格别名是另一回事。使用__restrict,您告诉编译器该函数中的特定两个指针不相互别名(实际上您说它们根本没有别名,但最重要的是它们不相互别名)。这对你来说是真实而明显的,但对编译器来说并不明显。如果编译器不知道,它必须假设最坏的情况。最坏的情况是他们做别名,这意味着许多优化假设是不安全的假设。这会阻碍矢量化并需要冗余负载。
【解决方案2】:

这不是您问题的真正答案;而是关于如何完全避免这个问题的建议。

您提到您使用的是 OS X;该平台上已经有提供您正在查看的操作的 API,无需自动矢量化。是否有某些原因您不使用它们?自动矢量化确实很酷,但它需要一些工作,而且通常它产生的结果不如使用已经为您矢量化的 API 好。

#include <string.h>
#include <Accelerate/Accelerate.h>

int main() {

    int n = 256;
    float a[256],
    b[256];

    // You can initialize the elements of a vector to a set value using memset_pattern:
    float threehalves = 1.5f;
    memset_pattern4(a, &threehalves, 4*n);

    // Since you have a fixed exponent for all of the base values, we will use
    // the vImage gamma functions.  If you wanted to have different exponents
    // for each input (i.e. from an array of exponents), you would use the vForce
    // vvpowf( ) function instead (also part of Accelerate).
    //
    // If you don't need full accuracy, replace kvImageGamma_UseGammaValue with
    // kvImageGamma_UseGammaValue_half_precision to get better performance.
    GammaFunction func = vImageCreateGammaFunction(2.3f, kvImageGamma_UseGammaValue, 0);
    vImage_Buffer src = { .data = a, .height = 1, .width = n, .rowBytes = 4*n };
    vImage_Buffer dst = { .data = b, .height = 1, .width = n, .rowBytes = 4*n };
    vImageGamma_PlanarF(&src, &dst, func, 0);
    vImageDestroyGammaFunction(func);

    // To simply square a instead, use the vDSP_vsq function.
    vDSP_vsq(a, 1, b, 1, n);

    return 0;
}

更一般地说,除非您的算法非常简单,否则自动矢量化不太可能产生很好的结果。根据我的经验,矢量化技术的范围通常如下所示:

better performance                                            worse performance
more effort                                                         less effort
+------+------+----------------------+----------------------------+-----------+
|      |      |                      |                            |           |
|      |  use vectorized APIs        |                   auto vectorization   |
|  skilled vector C                  |                              scalar code
hand written assembly       unskilled vector C

【讨论】:

  • 我在 OS X 上开发,但不一定为 os x 开发(预期目标是 centos 5)。此外,我试图不引入许多其他库。不过感谢 OS X api - 我可以将它用于我正在工作的其他事情。
  • @Misha:我假设那些会打扰的人知道他们在做什么,但是是的 =)
猜你喜欢
  • 1970-01-01
  • 2017-06-10
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 2018-12-16
  • 1970-01-01
相关资源
最近更新 更多