你会如何优化这个功能?

时间:2016-09-29 13:11:48

标签: c++ c optimization branch-prediction

#include <stdlib.h> 
#include <cstring.h>
#include <time.h>

int cp[1000000][3];
int p[1000000][3];//assume this array to be populated

void  main(){

srand(time(NULL));

for(n; n < 1000000; n++){
    if (rand()%2)
        memcpy(cp[n], p[n], 12);
    }
}

}

这是我正在使用的实际代码的简化版本。这段代码占据了我的过程的重要部分我想知道我是否可以通过一些聪明的技巧来优化它。我之前使用过指针来避免分支,但我无法弄清楚如何在这里应用它。

3 个答案:

答案 0 :(得分:4)

摆脱浮点是你应该做的一个明显的改进。那部分看起来很可疑,我假设您希望代码复制数据的概率为50%?

分支本身可以通过一些愚蠢的技巧删除:

int do_copy = rand() % 2;
memcpy(cp[n], p[n], 12*do_copy);

但是,如果不首先查看优化代码的反汇编,我就不会编写这样的代码。

答案 1 :(得分:1)

rand()很可能是此代码的瓶颈。由于您只需要二元决策,因此请考虑使用单个随机数的所有位来分摊随机数生成的成本。

for(int n=0; n<1000000; n+=NUM_BITS){
    uint32_t rand_val = static_cast<uint32_t>(rand()); // Edited based on comments
    for(int j=0; j<NUM_BITS; j++) {
        if((rand_val >> j) % 2) {
            memcpy(cp[n+j], p[n+j], 12);
        }
    }
}

唯一的诀窍是从NUM_BITS找出RAND_MAX,并决定你想要的高品质和便携性。选择NUM_BITS,以便1<<NUM_BITS小于RAND_MAX。请注意,此版本假定将NUM_BITS均分为样本总数。检查此限制或编写循环序言以容纳部分保留作为OP的练习。

我的Linux文档警告我,rand()的旧版本对于该数字的所有位都没有高质量的随机性,但它现在已经修复。如果您关心高质量的随机性,请注意这一点。

如果随机性质不是特别重要,您也可以寻找更快的随机生成器(它们存在)。

答案 2 :(得分:1)

很难提供完整的答案。

  1. (评论)我假设rand只是外部50/50决策的占位符,也不是生产用途?
  2. 否则,请注意rand()很糟糕。让匆忙的数字随机变成蠢货是很好的。避免浮点除法。 rand()%2通常比rand()&gt; RAND_MAX / 2差一点,但这种差异很少发生。

    1. (评论)你假设sizeof(int)== 4。不太好。

    2. 有没有理由不只是复制整个缓冲区?

    3. 单个大型副本可能比许多小型副本快,即使它接触数据的两倍。

      即。如果未使用未复制的元素,原始数据是否在那里并不重要。 OTOH,如果不能覆盖未复制的元素,则不适用。

      1. 用3个整数赋值替换memcpy。
      2. 好的编译器应该能够在像你这样的大多数场景中做到这一点,但是memcpy会变得有点复杂。 (它需要检查奇数长度,可能需要检查未对齐的读取等)。

        这允许三个分配并行使用每个核心的多个单元。

        1. 并行化(但缓存)的大优化潜力
        2. 如果你可以使随机数生成非顺序 - 例如通过使用4个独立的生成器 - 可以在多个线程上分配负载,每个线程处理一个数据块。

          1. 可以通过复制到虚拟缓冲区来避免分支
          2. 这是一个有趣的想法,但我不确定它是否会给你买得太多,但是:

            int dummyBuffer[3];
            for(...)
            {
              int * target = (rand() % 2) ? dummyBuffer : cp+n;
              //  <-- replace with arithmetic trickery to avoid the branch
              target[0] = p[n][0];
              target[1] = p[n][1];
              target[2] = p[n][2];
            }
            

            (正如所写的那样,分支将被转移到&#34; target&#34;的分配,而不是很多胜利。但是,你可能知道/可以构造一些技巧来使这个分配无分支)< / p>