分支错误预测是否会刷新整个管道,即使对于非常短的 if 语句体也是如此?

2024-01-04

我读到的所有内容似乎都表明分支预测错误总是会导致整个管道被刷新,这意味着大量的周期被浪费。我从未听到任何人提到过短 if 条件的任何例外情况。

在某些情况下这似乎真的很浪费。例如,假设您有一个单独的 if 语句,其主体非常简单,被编译为 1 个 CPU 指令。 if 子句将被编译为一条指令的条件向前跳转。如果CPU预测该分支不会被执行,那么它将开始执行if-body指令,并且可以立即开始执行后面的指令。现在,一旦 if 条件的评估到达管道末端(可能是 12 个周期后),CPU 现在就知道它的预测是正确还是错误。如果它预测错误,并且分支确实被采用,那么 CPU 实际上只需丢弃管道中的 1 条指令(if 主体中的指令)。但是,如果它刷新整个管道,那么按照以下指令完成的所有工作也都被浪费了,并且必须无缘无故地重复。在深度流水线架构中,存在大量浪费的周期。

那么,现代 CPU 是否有任何机制可以仅丢弃短 if 主体内的少数指令呢?或者它真的冲洗了整个管道吗?如果是后者,那么我想使用条件移动指令会获得更好的性能。顺便说一句,有谁知道现代编译器是否擅长将短 if 语句转换为 cmov 指令?


大多数通用处理器确实会在分支预测错误时刷新管道。条件分支对性能的负面影响除了对分支预测的广泛研究(以及与其他技术一样)。 (Mark Smotherman 关于热切执行的页面 http://people.cs.clemson.edu/~mark/eager.html提供了一些细节和参考。我会将 Hyesoon Kim 等人的“Wish Branches: Combining Conditional Branching and Predicate for Adaptive Predicated Execution”(2005 年)添加为重要论文。)

IBM 的 POWER7 似乎是第一个实现比预取替代路径(即急切取)更复杂的功能的主流处理器,并且它只处理单指令情况。 (POWER7 使用分支预测置信度估计来选择是进行谓词还是使用预测。)

急切执行具有明显的资源使用爆炸性问题。即使基于分支预测置信度、推测深度和资源可用性(前端可用的信息)的选择性渴望,沿着单一路径进行更深入的推测也很容易变得更有效。发现多条路径的连接点并避免过多的冗余计算也会增加复杂性。 (理想情况下,独立于控制的操作只会执行一次,并且会优化连接和数据流,但这种优化会增加复杂性。)

对于深度流水线的有序处理器,预测短的前向分支不被采用并且仅在实际采用分支时才在流水线中向后刷新到所采用的分支的目标指令似乎很有吸引力。如果管道中一次只允许一个这样的分支(其他分支使用预测),则向每条指令添加一位可以控制是将其转换为 nop 还是执行。 (如果只处理单个指令分支的情况,那么在管道中允许多个分支可能不会特别复杂。)

这类似于“如果采取则取消”分支延迟时隙。 MIPS 有“可能分支”指令,如果not已采取,并且这些在修订版 2.62 中被标记为已过时。虽然这样做的一些理由大概是为了将实现与接口分开以及恢复指令编码空间的愿望,但这一决定也暗示该概念存在一些问题。

如果对所有短前向分支都执行此操作,则当分支被正确预测为采用时,它将丢弃指令。 (请注意,如果所采用的分支总是在取指重定向中遇到延迟,则这种惩罚可能会更小,这在深度流水线处理器中的多周期指令缓存访问中更可能发生。在这种情况下,就好像没有分支一样进行取指可以具有与正确预测的采用分支相同的性能。但是,有人可能会争辩说,处理器特殊情况如此短的采用分支可以最大限度地减少此类获取气泡。)

作为一个例子,考虑一个标量管道(每个周期的非分支指令等于 1.0),在第八阶段结束时进行分支解析,并且在正确预测的采用分支上没有获取重定向惩罚,处理单指令分支。假设此类短前向分支(指令的 2%,占用 30% 的时间)的分支预测器准确度为 75%(不受方向影响),其他分支(指令的 18%)的准确度为 93%。对于错误预测为采用的短分支,将节省 8 个周期(此类分支的 17.5%;指令的 0.35%),如果错误预测为未采用,则将节省 7 个周期(7.2%;0.144%),而正确时将丢失 1 个周期预测为实际情况(22.5%;0.45%)。每条指令总共将节省 0.03358 个周期。如果没有这种优化,每条指令的周期将为 1.2758。

(虽然上面的数字只是举例,但除了用于非分支指令的 1.0 IPC 之外,它们可能与现实相距不远。提供小型循环缓存将减少误预测损失(并在短循环中节省功耗),因为指令缓存访问可能是八个周期中的三个。添加缓存未命中的影响将进一步减少此分支优化的百分比改进。避免预测“强烈采用”短分支的开销might是值得的。)

为了降低设计、功耗和面积成本,设计倾向于使用较窄和较浅的管道,并且更喜欢简单性。由于指令集可能支持许多短分支情况的无分支代码,因此优化这方面的动力进一步降低。

对于无序实现,必须预测潜在的分支指令,因为处理器希望能够执行以后的非相关指令。预测引入了额外的数据依赖性,必须检查该数据依赖性以进行调度。指令调度器通常为每条指令仅提供两个比较器并拆分条件移动(仅具有三个数据流操作数的简单指令:旧值、替代值和条件;谓词寄存器寄存器加法将具有四个操作数。(有其他方法可以解决这个问题,但这个答案已经很长了。)

当分支条件不可用时,无序实现也不会停止。这是控制依赖性和数据依赖性之间的权衡。通过准确的分支预测,控制依赖性非常便宜,但数据依赖性可以阻止等待数据操作数的前进进度。 (当然,通过布尔数据依赖性,值预测变得更有吸引力。在某些情况下使用谓词预测可能是可取的,并且比使用动态成本和置信度估计的简单预测具有优势。)

(也许很能说明问题的是,ARM 选择放弃 64 位 AArch64 中的大量预测。虽然其中很大一部分用于指令编码,但预测对高性能实现的好处可能相对较低。)

编译器问题

无分支与分支代码的性能取决于分支的可预测性和其他因素(如果采取的话,包括重定向获取的任何惩罚),但编译器很难确定分支的可预测性。即使概况数据通常也仅提供分支频率,这可能给出可预测性的悲观观点,因为这没有考虑使用局部或全局历史的分支预测器。编译器也不能完全了解数据可用性的时间和其他动态方面。如果条件晚于用于计算的操作数可用,则用数据依赖(预测)替换控制依赖(分支预测)可能会降低性能。无分支代码还可能引入更多实时值,从而可能增加寄存器溢出和填充开销。

更复杂的是,大多数仅提供条件移动或选择指令的指令集不提供条件存储。虽然可以通过使用条件移动来选择安全的、被忽略的存储位置来解决这个问题,但这似乎是一个没有吸引力的复杂化。此外,条件移动指令通常比简单的算术指令更昂贵;加法和条件移动可能需要三个周期,而正确预测的分支和加法将需要零(如果加法分支)或一个周期。

更复杂的是分支预测器通常会忽略谓词操作。如果后来保留的分支与删除的分支的条件相关,则该后来的分支的分支错误预测率可能会增加。 (谓词预测可用于保留此类删除分支的预测器效果。)

随着对向量化的日益重视,无分支代码的使用变得更加重要,因为基于分支的代码限制了在整个向量上使用操作的能力。

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

分支错误预测是否会刷新整个管道,即使对于非常短的 if 语句体也是如此? 的相关文章

  • 更改为通用接口对性能的影响

    我使用 Visual Studio 使用 C NET 开发应用程序 ReSharper 在我的方法原型中经常建议我用更通用的类型替换输入参数的类型 例如 如果我仅在方法主体中使用带有 foreach 的列表 则使用 List 和 IEnum
  • 如何加快编辑距离计算速度

    我正在尝试运行模拟来测试平均值编辑距离 http en wikipedia org wiki Levenshtein distance之间随机 二进制字符串 我的程序是用 python 编写的 但我正在使用这个C扩展 https githu
  • Git:在本地合并远程分支

    我已经通过以下方式拉取了所有远程分支git fetch all 我可以看到我想要合并的分支git branch a作为远程 原点 分支名称 问题是它无法访问 我无法合并或结帐 您可以参考那些远程跟踪分支 列出git branch r 及其遥
  • 按类型进行弹簧接线比按名称接线要慢很多

    在我的项目中 我试图迁移 Foo foo Foo beanFactory getBean name into Foo foo beanFactory getBean Foo class 好处是显而易见的 类型安全 更少复杂的代码 更少无用的
  • STL 容器速度与数组

    我刚刚开始从事一个科学项目 其中速度非常重要 HPC 我目前正在设计数据结构 该项目的核心是双值 3D 网格 以求解偏微分方程 由于这里的速度可能比代码的简单性更重要 我想知道 STL 与通常的 C 风格数组相比如何执行 就我而言 因为它是
  • 使用map.get()时使用java Map.containsKey()是多余的

    一段时间以来 我一直想知道在最佳实践中是否允许避免使用containsKey 方法上java util Map而是对结果进行空检查get 我的理由是 两次查找值似乎是多余的 首先是查找containsKey 然后再次为get 另一方面 大多
  • 去除字符串的最佳方法是什么?

    我需要具有最佳性能的想法来删除 过滤字符串 I have string Input view 512 3 159 删除 view 和 的最佳性能方法是什么 和引号 我可以做这个 Input Input Replace view Replac
  • __stack_chk_fail_local 和 -fno-stack-protector - 如何让它工作?

    Update 我刚刚发现问题出在我的项目 libxml2 中包含的预构建库上 它是在启用堆栈保护的情况下构建的 因此依赖于 stack chk fail local方法 我现在已经重建了该库 fno stack protector也是 一切
  • IEnumerable 作为 DataTable 性能问题

    我有以下扩展 它生成一个DataTable从一个IEnumerable public static DataTable AsDataTable
  • 从视频创建缩略图 - 提高速度性能 - AVAsset - iPhone [重复]

    这个问题在这里已经有答案了 我正在使用基于以下线程中的代码的代码来生成视频缩略图 从 iPhone SDK 中的视频 URL 或数据获取缩略图 https stackoverflow com questions 1347562 gettin
  • iOS 自定义单元格设计放在哪里? awakeFromNib 还是 cellForRowAtIndexPath?

    所以 基本上我用笔尖做了一个定制单元 希望我应用一些定制设计 比如颜色和阴影 我发现了两种应用样式的方法 awakeFromNib override func awakeFromNib super awakeFromNib Containe
  • 嵌套辅助函数和性能

    嵌套辅助函数对于使代码更易于理解非常有用 谷歌甚至建议在他们的应用程序中使用嵌套函数时尚指南 https google styleguide googlecode com svn trunk javascriptguide xml Nest
  • Haswell 及其后续产品上的 A20 系列是否仍会被屏蔽?

    维基百科引用了英特尔手册中的这一说法 A20M 的功能主要由较旧的操作系统使用 现代操作系统不使用 在较新的 Intel 64 处理器上 A20M 可能不存在 现在的手册中实际上有这样一个短语 但它是含糊不清的 Does A20M 实际上仅
  • Java ByteBuffer 性能问题

    在处理多个千兆字节文件时 我注意到一些奇怪的事情 似乎使用文件通道从文件读取到使用 allocateDirect 分配的重用 ByteBuffer 对象比从 MappedByteBuffer 读取要慢得多 事实上它甚至比读取到字节还要慢使用
  • jQuery mousemove 性能 - 节流事件?

    我们面临着与 mousemove 连接的 jQuery 事件传播性能问题 我们有一个屏幕填充画布 需要跟踪用户是否在其上拖动鼠标 因此我们在该对象上添加了一个鼠标移动侦听器 如下所示 ourCanvas on mousemove funct
  • x86 中有加速 SHA (SHA1/2/256/512) 编码的指令吗?

    一个例子 在x86 是硬件加速 AES 的指令集 http en wikipedia org wiki AES instruction set 但是x86中是否有加速SHA SHA1 2 256 512 编码的指令 以及在x86上编码SHA
  • Java 11 中使用堆栈跟踪的速度明显慢于 Java 8

    我正在比较 JDK 8 和 11 的性能jmh https openjdk java net projects code tools jmh 1 21 当我遇到一些令人惊讶的数字时 Java version 1 8 0 192 vendor
  • 如何从内存加载值而不污染缓存?

    我想读取内存位置而不污染缓存 我正在 X86 Linux 机器上工作 我尝试使用 MOVNTDQA 汇编指令 asm movntdqa source dest n t dest x my var source m my mem 0 memo
  • 与保留模式 GUI 相比,使用立即模式 GUI 对性能有何影响?

    我目前正在开发一个标准的 Windows 桌面应用程序 标准意味着没有花哨的东西 只是按钮 文本 滑块等 在研究了一些 GUI 框架并被拒绝后 我决定自己编写一个 GUI 框架他们全部 由于这是一个业余爱好项目 我也愿意尝试 并决定将 GU
  • JSON.stringify 对于大型对象来说非常慢

    我在 javascript 中有一个非常大的对象 大约 10MB 当我对其进行字符串化时 需要很长时间 因此我将其发送到后端并将其解析为一个对象 实际上是带有数组的嵌套对象 这也需要很长时间 但这不是我们在这个问题中的问题 问题 我怎样才能

随机推荐

  • 这种线程间通信的方法安全吗?

    我有3个对象 继承自QObject 每个都包含一个单独的std list 每个对象都是在主 gui 线程 没有父线程 中创建的 然后被推送到它自己的线程 使用 Qt 的QObject moveToThread 每个线程都连接到一个 GUI
  • Google 在 Github 页面上找不到 Analytics 代码片段 [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 一段时间以来 我一直无法让 Google Analytics 在我生成的 Github 页面上正常工作 我使用了 Google 提供的默认代码段 但我
  • pandas ols 导入损坏?

    我试图在 pandas 0 9 1 中执行 OLS 但出现此错误 ipdb gt foo ols y df y var 1 x df x var pool False ImportError No module named scikits
  • 如何使SQL Server 2008表的检查约束仅允许某些字符?

    我想在 SQL 2008 中为表创建一个检查约束 该约束允许使用 A Z 字符 不区分大小写 数字 连字符 点 空格和下划线 下面是我现在的表情 company code 不像 A Za z0 9 它满足除连字符之外的所有上述要求 我怎样才
  • Apache Tika 无法正确检测 MIME 类型

    我试图在使用inn上传文件时检测文件类型Apache Tika如下所示 static final List
  • 在 iframe 中设置 cookie - 不同的域

    我们将我们的网站作为 iframe 集成到在不同域上运行的另一个网站中 看来我们不能设置cookie 以前有人遇到过这个问题吗 有任何想法吗 由于您的内容是从远程域加载到 iframe 中 因此它被归类为第三方cookie 绝大多数第三方
  • Dexie 数据库超时变慢

    我正在将 Dexie DB 版本 2 0 4 与 Angular 8 和 Electron 一起使用 我意识到 在数据库中输入的数据越多 对其进行的查询越多 数据库调用就会变得越慢 我是一个 Dexie 菜鸟 不确定在发出某些请求后是否有办
  • 如何从 NLTK 导入和使用停用词列表?

    我已经导入了stopwords from nltk corpus 但我得到STOPWORDS is not defined错误 下面是我的代码 import nltk from nltk corpus import stopwords Cr
  • 如何在 Javascript 中以编程方式创建控制字符?

    在 Javascript 中我可以输入 u00A3 使用字符代码获取字符 我可以通过编程来执行此操作String fromCharCode parseInt 00A3 16 但我找不到对控制角色执行相同操作的方法 我可以在源代码中输入它们
  • 错误:$controller:ctrlreg 未注册名为“{0}”的控制器

    app js function use strict angular module app ngRoute ngCookies config config config inject routeProvider locationProvid
  • 为什么数组是不变的,而列表是协变的?

    例如 为什么 val list List Any List Int 1 2 3 工作 但是 val arr Array Any Array Int 1 2 3 失败 因为数组是不变的 这个设计决策背后的预期效果是什么 因为否则它会破坏类型安
  • 使用子项目构建 Android Gradle

    我目前正在将我们的一个项目从 Maven 转换为 Gradle 文件夹结构如下 gitRoot settings gradle build gradle ProjectA build gradle src main java Librari
  • 没有这样的模块“Flutter”[重复]

    这个问题在这里已经有答案了 我已经在 TestFlight 中发布了我的应用程序 但它在启动时崩溃 当我查看崩溃日志时 它说 没有这样的模块 Flutter 我确实知道如何修复 Thanks in Advance 在终端中打开 IOS 文件
  • 通过指针传递二维数组

    如何将 m 矩阵传递给 foo 如果我不允许更改 foo 的代码或原型 void foo float pm int i j for i 0 i lt 4 i for j 0 j lt 4 j printf f n pm i j int ma
  • 如何在 R 中从 PDF 绘制 CDF 函数

    我有以下功能 fx lt function x if x gt 0 x lt 3 res lt 0 2 else if x gt 3 x lt 5 res lt 0 05 else if x gt 5 x lt 6 res lt 0 15
  • 星号 (*) 在 CSS 选择器中起什么作用?

    我找到了这段 CSS 代码 并运行它来查看它的作用 它概述了页面上的每个元素 谁能解释一下星号是什么 CSS 中有吗
  • 充气城堡:如何获取带有调试信息的 bcpkix-jdk15on-1.47.jar

    我正在尝试调试充气城堡 1 47 的问题 我可以找到 bcprov 的调试 jar 但找不到 org bouncycastle bcpkix jdk15on 1 47 jar 的调试 jar 还有其他地方可以下载带有调试信息的 bcpkix
  • 如何从本地 cocoapods 缓存中清除或清除特定 pod

    如何从 cocoapods 缓存中删除或清除特定的 pod 尝试直接删除整个缓存 需要很长时间才能恢复所有 Pod 如何从缓存中查看和删除特定的 Pod 以下作品 较长时间提交 delete all cached pods rm rf HO
  • 在 Xcode 4 中重定向 I/O

    我刚刚安装了 Xcode 4 我正在尝试将输入从文件重定向到我的 C 程序 我尝试在运行方案的 参数 部分中使用常用的 Thanks Samer 我使用各种类型的参数进行了测试 似乎 Xcode 在参数方面存在错误 上次测试 Xcode 8
  • 分支错误预测是否会刷新整个管道,即使对于非常短的 if 语句体也是如此?

    我读到的所有内容似乎都表明分支预测错误总是会导致整个管道被刷新 这意味着大量的周期被浪费 我从未听到任何人提到过短 if 条件的任何例外情况 在某些情况下这似乎真的很浪费 例如 假设您有一个单独的 if 语句 其主体非常简单 被编译为 1