将rdmsr / rdpmc用于分支预测精度

问题描述 投票:2回答:2

我试图了解分支预测单元如何在CPU中工作。

我使用过papi,也使用过Linux的perf-events,但它们都不能给出准确的结果(就我而言)。

这是我的代码:

void func(int* arr, int sequence_len){
  for(int i = 0; i < sequence_len; i++){
      // region starts
      if(arr[i]){
          do_sth();
      }
      // region ends
  }
}

我的数组由0和1组成。它具有大小为sequence_len的图案。例如,如果我的尺寸为8,则其样式为0 1 0 1 0 0 1 1或类似的样式。

审判1:

我试图了解CPU如何预测那些分支。因此,我使用了papi并为错误的分支预测设置了性能计数器(我知道它也计算间接分支)。

int func(){
  papi_read(r1);
  for(){
    //... same as above
  }
  papi_read(r2);
  return r2-r1;
}

int main(){
   init_papi();
   for(int i = 0; i < 10; i++)
     res[i] = func();

   print(res[i]);
}

我看到的是输出(序列长度为200)

100 #iter1
40  #iter2
10  #iter3
3
0
0
#...

因此,起初,CPU会盲目地预测序列,只有一半时间成功。在接下来的迭代中,CPU可以预测得越来越好。经过一些迭代之后,CPU可以完美地猜测出来。

审判2

我想看看,在哪个数组索引上发生CPU错误预测。

int* func(){
  int* results;
  for(){
    papi_read(r1);
    if(arr[i])
        do_sth();   
    papi_read(r2);
    res[i] = r2-r1;
  }
  return res;
}

int main(){
   init_papi();
   for(int i = 0; i < 10; i++)
     res[i] = func();

   print(res[i]);
}

预期结果:

#1st iteration, 0 means no mispred, 1 means mispred
1 0 0 1 1 0 0 0 1 1 0... # total of 200 results
Mispred: 100/200
#2nd iteration
0 0 0 0 1 0 0 0 1 0 0... # total of 200 results
Mispred: 40/200 # it learned from previous iteration
#3rd iteration
0 0 0 0 0 0 0 0 1 0 0... # total of 200 results
Mispred: 10/200 # continues to learn
#...

接收结果:

#1st iteration
1 0 0 1 1 0 0 0 1 1 0... # total of 200 results
Mispred: 100/200
#2nd iteration
1 0 0 0 1 1 0 1 0 0 0... # total of 200 results
Mispred: 100/200 # it DID NOT learn from previous iteration
#3rd iteration
0 1 0 1 0 1 0 1 1 0 0... # total of 200 results
Mispred: 100/200 # NO LEARNING
#...

我的观察

[当我在for循环之外测量错误预测时,我可以看到CPU从其错误预测中学习。但是,当我尝试测量单个分支指令的错误预测时,CPU要么无法学习,要么我测量错误。

我的解释

我给出200作为序列长度。 CPU具有一个小型分支预测器,例如Intel中的2-3位饱和计数器,以及一个大型全局分支预测器。当我在环路外进行测量时,会给测量引入更少的噪声。噪音越小,我的意思是papi通话。

考虑这一点:环路测量之外

全局历史为:papi_start, branch_outcome1, branch_outcome2, branch_outcome3, ..., papi_end, papi_start (2nd loop of main iteration), branch_outcome1, ...

因此,分支预测变量以某种方式在同一分支中找到模式。

但是,如果我尝试测量单个分支指令,则全局历史记录为:papi_start, branchoutcome1, papiend, papistart, branchoutcome2, papiend...

因此,我正在向全球历史介绍越来越多的分支机构。我认为全局历史记录不能容纳许多分支条目,因此,它无法在所需的if语句(分支)中找到任何相关性/模式。

结果

我需要测量单个分支的预测结果。我知道,如果我不过多引入papi,CPU可以学习200模式。我查看了papi调用,并且看到了许多for循环(如果有条件的话)。

这就是为什么我需要更好的测量。我尝试了linux perf-event,但是它进行了ioctl调用,这是一个系统调用,并且我使用系统调用来污染全局历史记录,因此不是一个很好的衡量标准。

我已经阅读了rdpmcrdmsr指令,并且由于它们仅是指令,因此我不会污染全局历史记录,并且可以一次测量单个分支指令。

但是,我不知道该怎么做。我有AMD 3600 CPU。这些是我在网上找到的链接,但我不知道该怎么做。除此之外,我还缺少什么吗?

Intel rdpmc

AMD Performance manual

我试图了解分支预测单元如何在CPU中工作。我已经使用了papi和linux的perf-events,但是它们都不能给出准确的结果(就我而言)。这是我的代码:...

c x86 performancecounter branch-prediction papi
2个回答
0
投票

您已经假设PAPI和/或perf_events代码具有相对较小的占用空间。这是不正确的。如果将性能计数器事件更改为“指令已退休”或“ CPU周期未暂停”之类的内容,则可以查看此操作在软件环境中包含多少开销。详细信息将取决于您的OS版本,但是我希望开销在数百个指令/数千个周期中,因为读取perf_events(由PAPI使用)中的计数器所需的内核交叉。代码路径肯定会包含其自己的分支。


0
投票

我发现如何使用Linux perf_event_open()rdpmc并不明显。

© www.soinside.com 2019 - 2024. All rights reserved.