分支错误预测是否会刷新整个管道,即使对于非常短的 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 语句体也是如此? 的相关文章

  • 优化 LATERAL join 中的慢速聚合

    在我的 PostgreSQL 9 6 2 数据库中 我有一个查询 该查询根据一些股票数据构建计算字段表 它为表中的每一行计算 1 到 10 年的移动平均窗口 并将其用于周期性调整 具体来说 CAPE CAPB CAPC CAPS 和 CAP
  • 缓存一致性是否始终可以防止读取过时的值?失效队列允许吗?

    在 MESI 协议中 仅当将缓存行保持在独占 修改状态时才写入缓存行 要获取独占状态 您可以向持有同一高速缓存行的所有核心发送无效请求 但是是否存在一种微架构 其中某些内核会在实际使缓存线无效之前做出确认响应 如果确实如此 那不是违反了缓存
  • 为什么我的代码显示垃圾?

    当我也想打印列表中的每个数字时 我的代码显示垃圾 有什么问题吗 输出应如下所示 给定的数组是 2G 4 PT为什么这是垃圾总数是 7 Code ASSUME CS CODE DS DATA SS STK ORG 0000H DATA SEG
  • .pdbs 会减慢发布应用程序的速度吗?

    如果 dll 中包含 pdb 程序调试 文件 则行号将出现在引发的任何异常的堆栈跟踪中 这会影响应用程序的性能吗 这个问题与发布与调试 即优化 无关 这是关于拥有 pdb 文件的性能影响 每次抛出异常时都会读取 pdb 文件吗 加载程序集时
  • 如何最大限度地提高服务器性能?

    我一直在努力了解性能和可扩展性 并想知道开发人员 系统管理员正在做什么来提高他们的系统的效率 为了标准化答案 如果您能尽力回答以下任一问题 将会有所帮助 Profile Magazine publication on Joomla Jobs
  • Pandas dataframe:每批行的操作

    我有一个熊猫数据框df我想计算每批行的一些统计信息 例如 假设我有一个batch size 200000 对于每批batch sizerows 我想要一列的唯一值的数量ID我的数据框 我怎样才能做这样的事情呢 这是我想要的一个例子 prin
  • 文件修改时间检查的成本

    对于Linux下包含少量字节的文件 我只需要处理自上次处理以来发生更改的时间 我通过调用 PHP 检查文件是否被更改clearstatcache filemtime 定期 由于整个文件总是很小 因此删除对 filemtime 的调用并通过将
  • 添加冗余赋值可以在未经优化的情况下编译时加快代码速度

    我发现一个有趣的现象 include
  • 使用 FileInputStream 时如何确定理想的缓冲区大小?

    我有一个从文件创建 MessageDigest 哈希 的方法 我需要对很多文件 gt 100 000 执行此操作 用于读取文件的缓冲区应该设置多大才能最大限度地提高性能 大多数人都熟悉基本代码 为了以防万一 我将在这里重复一遍 Messag
  • NHibernate - CreateCriteria 与 CreateAlias

    假设以下场景 class Project public Job Job class Job public Name 假设我想使用 Criteria API 搜索其 Job 名称为 sumthing 的所有项目 我可以使用 CreateAli
  • SIMD 和 VLIW 指令是一样的吗?

    SIMD 单指令多数据 和 VLIW 超长指令字 到底有什么区别 其中一个是另一个的子集吗 或者它们是两个完全不同的东西 完全不相关且正交 一台机器可以有一个或两个 或者两者都没有 SIMD 指令可以作为扩展添加到 VLIW ISA 但 V
  • 如何提高包含大量小图像的 UCollectionView 的性能?

    在我的 iOS 应用程序中我有UICollectionView显示大约 1200 个小 35x35 点 图像 图像存储在应用程序包中 我正确地重用了UICollectionViewCell但仍然存在性能问题 具体取决于我处理图像加载的方式
  • 模块化算术和 NTT(有限域 DFT)优化

    我想使用 NTT 进行快速平方 参见快速大数平方计算 https stackoverflow com q 18465326 2521214 但即使对于非常大的数字 结果也很慢 超过 12000 位 所以我的问题是 有没有办法优化我的 NTT
  • 分支预测器和分支目标缓冲区如何共存?

    我的问题是它们如何在现代 CPU 架构中共存并协同工作 你把它稍微颠倒了 每次获取时 您都会索引到分支预测器 它会告诉您刚刚收到的指令是否will be解码为已采取的分支 如果没有 则获取下一个连续地址 但是 如果您的分支预测器说它将是一个
  • 为什么在连接两个字符串时 Python 比 C 更快?

    目前我想比较 Python 和 C 用来处理字符串的速度 我认为 C 应该比 Python 提供更好的性能 然而 我得到了完全相反的结果 这是 C 程序 include
  • 有没有更简单的方法来处理复选框?

    在 vb net 中 我有一个包含一组四个复选框的表单 每个复选框都表示 选中时 用户想要向其订单添加特殊指令 代码如下所示 If SpecialInstruction1CheckBox Checked Then AddSpecialIns
  • 使用 React.forwardRef 与自定义 ref prop 的价值

    我看到React forwardRef从反应文档来看 似乎是将引用传递给子功能组件的认可方式 const FancyButton React forwardRef props ref gt
  • Python if 与 try- except

    我想知道为什么下面程序中的 try except 比 if 慢 def tryway try while True alist pop except IndexError pass def ifway while True if alist
  • React Native:加载图像后应用程序性能不佳

    加载图像似乎没有问题 但是加载完毕后就出现问题了 在我的应用程序中 我在整个游戏中一张一张地加载卡片图像 一旦我加载了 40 张卡片图像 整个应用程序就会变得很慢 它总是发生在第 40 个图像处 当我在第 40 个图像之后继续加载更多卡片图
  • 当前的 x86 架构是否支持非临时加载(来自“正常”内存)?

    我知道有关此主题的多个问题 但是 我没有看到任何明确的答案或任何基准测量 因此 我创建了一个处理两个整数数组的简单程序 第一个数组a非常大 64 MB 第二个数组b很小 无法放入 L1 缓存 程序迭代a并将其元素添加到相应的元素中b在模块化

随机推荐

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

    我有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