分支预测如何精确地影响R?

时间:2019-10-15 16:53:21

标签: r performance benchmarking interpreter branch-prediction

一些参考文献:

这是此Why is processing a sorted array faster than processing an unsorted array?

的后续内容

标签中唯一与分支预测有些相关的帖子是此Why sampling matrix row is very slow?

问题解释:

我正在调查处理排序数组是否比处理未排序数组快(与JavaC中测试的问题相同-第一个链接),以查看分支预测是否影响{{ 1}}以相同的方式。

查看下面的基准示例:

R

带有1e7个元素的向量 具有1e8个元素的向量

问题:

  • 首先,我想知道为什么“ Sorted” 向量不是一直都是最快的,而且幅度却不如set.seed(128) #or making a vector with 1e7 myvec <- rnorm(1e8, 128, 128) myvecsorted <- sort(myvec) mysumU = 0 mysumS = 0 SvU <- microbenchmark::microbenchmark( Unsorted = for (i in 1:length(myvec)) { if (myvec[i] > 128) { mysumU = mysumU + myvec[i] } } , Sorted = for (i in 1:length(myvecsorted)) { if (myvecsorted[i] > 128) { mysumS = mysumS + myvecsorted[i] } } , times = 10) ggplot2::autoplot(SvU) 所示吗?
  • 第二,为什么排序的执行时间与未排序的执行时间相比变化更大?

N.B。 。我的CPU是 i7-6820HQ @ 2.70GHz Skylake,具有超线程的四核

更新:

要研究变异部分,我用1亿个元素的向量(Java进行了microbenchmark并重复了100次基准测试(n=1e8 )。这是该基准的关联图。

这是我的times=100

sessioninfo

1 个答案:

答案 0 :(得分:1)

解释器的开销以及成为的解释器,可以解释大部分平均差异。对于较高的差异,我没有任何解释。


R是一种解释型语言,不是JIT编译为Java之类的机器代码,也不是像C这样的提前编译的机器。(我对R的内部知识了解不多,只有CPU和性能方面,在此处进行很多的假设。)

在实际CPU硬件上运行的代码是 R解释器,而不完全是您的R程序。

R程序中的

控件依赖项(如if())在解释器中成为 data 依赖项。当前正在执行的只是在真实CPU上运行的解释器的数据。

R程序中的不同操作成为解释器中的控件依赖项。例如,对myvec[i]进行评估,然后+运算符很可能由解释器中的两个不同函数完成。还有>if()语句的单独函数。

经典的解释器循环基于从函数指针表中分派的间接分支。 CPU需要一个对许多最近使用的目标地址之一的预测。我不知道R是否使用像这样的单个间接分支,或者是否试图像将每个解释器块的末尾分派到下一个分支一样,而不是返回到主分派循环,从而变得更加幻想。

现代Intel CPU(例如Haswell和更高版本)具有IT-TAGE(间接捕获的几何历史记录长度)预测。沿执行路径的先前分支的已采用/未采用状态用作预测表的索引。这主要解决了解释器分支预测问题,使它可以做的出奇的出色,尤其是当解释的代码(在您的情况下为R代码)重复执行相同的操作时。

使用if()确实需要执行不同的操作,因此实际上仍然在R解释器中进行了一些分支当然,作为解释器,与在数组上进行简单的机器代码循环相比,它在每个步骤上要做的工作要多得多。

由于解释器的开销,额外的分支错误预测占总时间的比例要小得多


当然,您的两个测试都在相同的硬件上使用相同的解释器。我不知道您拥有哪种CPU。

如果它的Intel早于Haswell或AMD早于Zen,那么即使使用排序数组,也可能会出现很多错误的预测,除非该模式足够简单以使间接分支历史预测器可以锁定。这样可以将差异掩盖在更多的噪音中。

由于您确实看到了非常明显的差异,所以我猜测在排序情况下CPU不会预测太多,因此在未排序情况下它有变差的空间。