CPU内部并行化

时间:2015-02-27 11:58:45

标签: c++ c performance prng

我一直在玩Xorshift *随机数生成器,我偶然发现了this对它们属性的探索。从该网站引用(强调我的):

  

xorshift64 *生成器如何比xorshift1024 *生成器慢?

     

依赖关系。 xorshift64 *生成器的三个xor / shift必须按顺序执行,因为每个xor / shift取决于前一个的结果。在xorshift1024 *生成器中,两个xor / shift完全独立,可以由CPU内部并行化。我还怀疑较大的状态空间使CPU可以执行更积极的推测执行(实际上,xorshift128 *生成器比xorshift1024 *生成器慢)。

CPU声明内部的并行化意味着什么?我认为它意味着CPU将使用向量指令同时执行两个xor / shift,但我无法在编译器的汇编输出中看到这一点的证据。这是一个深度CPU流水线的事情吗?或者我应该能够看到生成的汇编程序中发生了什么?

1 个答案:

答案 0 :(得分:10)

是的,这是instruction-level parallelism的事情。

基本上这样的CPU将具有比每个单独指令所需的更多可用执行硬件,因此它会扩展到"一堆关于可用资源的指令,然后将结果合并回来,这样对于程序员来说,它看起来仍然是顺序发生的事情。

你能看到的,如果你擅长它,是两个相邻的指令,它们都有效,但没有依赖性。例如,它们可能仅在非重叠寄存器集上运行。对于这种情况,您可以猜测它们可能并行执行,从而导致该特定代码位的每周期指令值很高。

为了使这一点更加具体,让我们看一下你正在谈论的两段代码(同时:为我学习机会)。

这是xorshift64 *的核心:

x ^= x >> 12; // a
x ^= x << 25; // b
x ^= x >> 27; // c
return x * 2685821657736338717LL;

实际上,函数中的所有代码(x都是uint64_t)。很明显,每一行都在触及状态,并对其进行修改,因此每个语句都依赖于它前面的那个。相比之下,这里是xorshift1024 +:

uint64_t s0 = s[ p ];
uint64_t s1 = s[ p = ( p + 1 ) & 15 ];
s1 ^= s1 << 31; // a
s1 ^= s1 >> 11; // b
s0 ^= s0 >> 30; // c
return ( s[ p ] = s0 ^ s1 ) * 1181783497276652981LL;

此处,全局状态位于uint64_t s[16], p个变量中。考虑到这一点,它可能不是很清楚,但至少有些暗示,// c评论的行是而不是与之前的行共享任何状态。因此,它做了两个轮班和一个异或(即#34;工作&#34;),它独立于它之前正在进行的类似工作。因此,超标量处理器可能或多或少地并行运行这两条线。