【问题标题】:Optimize and vectorize random function in c在c中优化和矢量化随机函数
【发布时间】:2020-07-17 23:11:47
【问题描述】:

我编写了一个函数来生成伪随机数,但我的编译器没有向量化这个not vectorized: complicated access pattern。 我怎样才能实现编译器对此进行矢量化? 我使用命令gcc -O3 -ffast-math -funroll-all-loops -ftree-vectorize -fopt-info-vec-missed -lm -g $1 -o ${2}.O3

    unsigned int seed;
    unsigned int temp;
    #define val13 13
    unsigned int var1 = 214013;
    unsigned int var2 = 2531011;
    inline int myRandom() {
      seed = (var1*seed + var2);
      return (seed>>val13);
    }

如果我将代码更改为此,我会设法进行矢量化,但我没有得到预期的结果。

inline int myRandom() {
          return ((var1*seed + var2)>>val13);
        }

我怎样才能让编译器对这个函数进行向量化并得到预期的结果?

【问题讨论】:

  • var1var2 真的是变量吗?它们对我来说就像常数。也许您应该澄清一下编译器(以及我们其他人)。常量通常更容易优化。
  • @rici:将它们更改为常量会产生相同的编译器消息。
  • 另一种方法是在每个通道中单独运行生成器:对于 n 路矢量化,设置 n 个种子,然后在每个通道中运行不同的生成器(相同的函数,不同的种子)。这将产生与未矢量化版本不同的结果,因此是否合适将取决于您的需求。
  • @eric:是的,我不认为它会矢量化。但它可能会产生其他优化,无论如何这是一个好习惯。
  • @EricPostpischil 在给定的代码中,移位对种子没有影响,因此这不会导致问题,即应该可以在每个种子元素上应用f^4(尽管可能非常困难供编译器查看)。但是,我认为有更适合矢量化的 PRNG,例如 SIMDxorshift 或 SFMT(面向 SIMD 的快速梅森扭曲器)。

标签: c optimization random vectorization


【解决方案1】:

种子上的生成器函数f是一个线性同余生成器,很容易与自身组合实现f2 f3f4 等等。然后可以实现一个矢量化生成器,它从一个种子中准备一个初始矢量块,然后使用 fB 计算 B 中的结果 车道彼此独立。这是一个概念证明。可以进行各种修饰,例如保留种子向量而不是单个种子,以及修改 FillRandomVector 以处理任意 N

#include <stdio.h>
#include <stdlib.h>


#define Block   4   //  Number of lanes (elements) in a vector block.


static const unsigned int var1 = 214013;
static const unsigned int var2 = 2531011;


//  Original generator function, modified to take a pointer to the seed.
static inline int MyRandom(unsigned int *seed)
{
    *seed = var1 * *seed + var2;
    return *seed >> 13;
}


//  New parameters for a vectorized generator.
static unsigned int var1Vector;
static unsigned int var2Vector;


/*  Initialize parameters for vectorized generator by computing them from the
    scalar parameters.
*/
static void Initialize(void)
{
    var1Vector = 1;
    var2Vector = 0;
    for (int i = 0; i < Block; ++i)
    {
        var1Vector *= var1;
        var2Vector = var2Vector * var1 + var2;
    }
}


//  Fill array with generated numbers using scalar method.
static void FillRandomScalar(unsigned int *seed, size_t N, int *Destination)
{
    for (size_t n = 0; n < N; ++n)
        Destination[n] = MyRandom(seed);
}


/*  Fill array with generated numbers using vectorizable method.

    For proof of concept only, so handles only certain N:

        N must be a positive multiple of Block.
*/
static void FillRandomVector(unsigned int *seed, size_t N, int *Destination)
{
    //  Prepare a vector of seeds and generate the first block of results.
    unsigned seedVector[Block];
    unsigned int S = *seed;
    for (size_t n = 0; n < Block; ++n)
    {
        S = S * var1 + var2;
        seedVector[n] = S;
        Destination[n] = S >> 13;
    }

    //  Generate the remaining results using independent lanes.
    for (size_t n = Block; n < N; n += Block)
        for (size_t lane = 0; lane < Block; ++lane)
        {
            seedVector[lane] = seedVector[lane] * var1Vector + var2Vector;
            Destination[n + lane] = seedVector[lane] >> 13;
        }

    *seed = seedVector[Block-1];
}


#define N   100


int main(void)
{
    Initialize();

    int expected0[N], observed0[N];
    int expected1[N], observed1[N];

    unsigned int seed;

    seed = 17;
    FillRandomScalar(&seed, N, expected0);
    FillRandomScalar(&seed, N, expected1);

    seed = 17;
    FillRandomVector(&seed, N, observed0);
    FillRandomVector(&seed, N, observed1);

    for (size_t n = 0; n < N; ++n)
    {
        if (observed0[n] != expected0[n])
        {
            printf("observed0[%zu] = %d, but expected0 %d.\n",
                n, observed0[n], expected0[n]);
            exit(EXIT_FAILURE);
        }
    }
    for (size_t n = 0; n < N; ++n)
    {
        if (observed1[n] != expected1[n])
        {
            printf("observed1[%zu] = %d, but expected1 %d.\n",
                n, observed1[n], expected1[n]);
            exit(EXIT_FAILURE);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2018-08-19
    • 2016-02-26
    • 2020-07-17
    • 1970-01-01
    • 2013-05-01
    • 2013-07-14
    • 1970-01-01
    • 2020-04-06
    • 1970-01-01
    相关资源
    最近更新 更多