使用 rdmsr/rdpmc 提高分支预测精度

2024-04-03

我试图了解分支预测单元在 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或类似的东西。

Trial 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 可以完美地猜测出来。

Trial 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 calls.

考虑一下:循环外测量

全球历史是: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 循环和 if 条件。

这就是为什么我需要更好的测量。我试过Linuxperf-event但这使得ioctl调用,这是一个系统调用,我用系统调用污染了全局历史记录,因此,这不是一个好的测量方法。

我读过rdpmc and rdmsr指令,我假设因为它们只是指令,所以我不会污染全局历史,并且我可以一次测量单个分支指令。

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

英特尔rdpmc https://software.intel.com/en-us/forums/software-tuning-performance-optimization-platform-monitoring/topic/595214

AMD 性能手册 https://www.amd.com/system/files/TechDocs/56255_OSRR.pdf


您假设 PAPI 和/或 perf_events 代码的占用量相对较小。这是不正确的。如果将性能计数器事件更改为“指令退休”或“CPU 周期未停止”之类的内容,您将能够看到此操作在您的软件环境中包含多少开销。详细信息取决于您的操作系统版本,但我预计开销将达到数百条指令/数千个周期,因为读取 perf_events(由 PAPI 使用)中的计数器需要内核交叉。代码路径肯定会包含它自己的分支。

如果您的内核支持“用户模式 ​​RDPMC”(CR4.PCE=1),则可以使用单条指令读取性能计数器。示例可在https://github.com/jdmccalpin/low-overhead-timers https://github.com/jdmccalpin/low-overhead-timers.

即使将测量代码限制为本机 RDPMC 指令(以及保存结果的周围代码),测量也会破坏处理器管道。 RDPMC 是微编码指令。在 Ryzen 核心上,指令执行 20 个微操作,每 20 个周期具有一条指令的吞吐量。 (参考:https://www.agner.org/optimize/instruction_tables.pdf https://www.agner.org/optimize/instruction_tables.pdf)

任何细粒度的测量都具有挑战性,因为现代处理器的无序功能与用户代码交互的方式记录很少且难以预测。有关此主题的更多说明(也与 AMD 处理器相关)位于http://sites.utexas.edu/jdm4372/2018/07/23/comments-on-timing-short-code-sections-on-intel-processors/ http://sites.utexas.edu/jdm4372/2018/07/23/comments-on-timing-short-code-sections-on-intel-processors/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 rdmsr/rdpmc 提高分支预测精度 的相关文章

随机推荐

  • 如何在 Flutter 中添加图标的增加/配置粗细/粗体(FontWeight)

    我的 Flutter 应用程序中有一个图标 具体是后退图标 它看起来更轻 我想出于某种原因让它变得大胆 增加重量 Container child Icon Icons arrow back color Color 0xffffffff pa
  • 在jquery中获取选定tr的td值

    下面是我的桌子 table tr class chargeTR td charge1 td td charge2 td tr table 下面是我的 jQuery 调用 chargeTR each function this line wo
  • 跨域ajax请求后保留cookie

    一个 JavaScript 应用程序运行在10 0 0 1尝试通过跨域 ajax 调用来验证其用户 该请求如下所示 function test again ajax type GET url http example com userinf
  • 简单框架:重复注释(不同的命名空间)

    我有一个 Rss 提要 我想使用简单框架在 Java 中解析它 我遇到了两个同名元素的问题 但其中一个元素分配了命名空间 下面是一个 xml 示例
  • ActionScript 3 分析器和内存分析工具

    我正在使用 Adob e Flash CS 4 想知道是否有可用的分析器或内存分析工具 动作脚本 3 我知道有适用于 Flex 的工具 但是有适用于 Flash CS 4 的工具吗 谢谢 我确信那里有一个程序 仍在寻找我自己 但我 大多数
  • 如何从 Angular2 和 ng-bootstrap 组件中的 NgbTabSet 访问“select”方法?

    使用 Angular 2 3 1 和 ng bootstrap 1 0 0 alpha 18 我正在尝试以编程方式根据组件中的 ID 而不是模板内的 ID 选择选项卡 目标是从 url 中提取参数并使用它来选择 ngOnInit 中的选项卡
  • 在 Javascript 中从本地数据保存文件

    场景如下 用户来到我的网站并打开一个带有一些 JavaScript 功能的网页 用户通过javascript编辑数据 用户单击保存按钮来保存数据 事情是 他们似乎不需要下载这些数据 因为它已经在本地计算机上的 JavaScript 中 是否
  • 用于检测 .NET CF 3.5 并安装它的 Windows Mobile Cab 设置

    我使用 NET CF 3 5 等目标框架和 professional 6 SDK 开发了 windows mobile 6 professional 应用程序 还创建了其 SmartDeviceCab 文件 当我将其安装在没有 CF 3 5
  • 如何控制.NET SoapFormatter中的命名空间?

    我正在编写一些需要向后兼容使用 SOAP 序列化某些对象的现有远程处理代码的代码 我的困难是我必须将一些对象移动到新程序集 因此远程处理被破坏 例如 我使用 NET SoapFormatter 序列化一个对象 如下所示 Person p n
  • vim 正则表达式用于替换引号内的空格

    我有以下格式的文本 ERR OUT OF MEM ERR OUT OF MEM ERR SOMETHING BAD ERR SOMETHING BAD 我想用下划线替换文本中引号内的所有空格 ERR OUT OF MEM ERR OUT O
  • MVVM 最佳实践:视图模型之间的通信

    我的简化程序结构如下所示 public class Manager public Item MyItem get set public void Recalculate public class Item public string Som
  • 每对观测值的马氏距离

    我正在尝试计算数据集的每个观测值之间的马哈拉诺比斯距离dat 其中每行是一个观察值 每列是一个变量 该距离定义为 我写了一个函数来做到这一点 但我觉得它很慢 在 R 中是否有更好的方法来计算它 生成一些数据来测试该功能 generateDa
  • 这个正则表达式不应该发生灾难性的回溯

    有人可以解释为什么 Java 的正则表达式引擎会在此正则表达式上进入灾难性的回溯模式吗 据我所知 每个交替都与其他每个交替相互排斥 s s Text p o de a car itaucard mastercard platinum SUS
  • 如何在Python 3.6中执行2个协程

    我无法让两个协程在我的 Python 3 6 程序中并行执行 这是一个例子 import asyncio time def main loop asyncio get event loop loop run until complete s
  • 查找C++静态初始化顺序问题

    我们遇到了一些问题静态初始化顺序惨败 http www parashift com c faq lite static init order html 并且我正在寻找方法来梳理大量代码以查找可能发生的情况 关于如何有效地做到这一点有什么建议
  • Cypher 查询 JSON 格式的结果

    在演员 电影演示图上 cypher 在单独的数组中返回列名称 MATCH n Person RETURN n name as Name n born as Born ORDER BY n born LIMIT 5 results colum
  • Mysql查询查找具有相同列值的字段之和

    我有一张这样的桌子 id invent id order 1 95948214 70 2 46018572 30 3 46018572 20 4 46018572 50 5 36025764 60 6 36025764 70 7 95948
  • Java音乐播放器:歌曲信息和播放[关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 在Android中 我们可以使用媒体播放器在设备上播放歌曲 并使用光标来获取曲目信息 操作系统跟踪的信
  • 简单登录返回空白页

    我正在学习 PHP 并且制作了一个简单的登录脚本 但问题是它仅将我重定向到空白页面 如果用户凭据正确 它的意思是重定向到index php 但情况显然并非如此 还有验证 如果用户输入空白 则会返回错误 这似乎没有被执行 登录 php
  • 使用 rdmsr/rdpmc 提高分支预测精度

    我试图了解分支预测单元在 CPU 中如何工作 我用过papi还有linux的perf events但他们都没有给出准确的结果 对于我的情况 这是我的代码 void func int arr int sequence len for int