- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
作为我对问题The advantages of using 32bit registers/instructions in x86-64的跟进,我开始衡量指导费用。我知道这已经完成了多次(例如Agner Fog),但我这样做是出于娱乐和自我教育的目的。
我的测试代码非常简单(为简化起见,此处为伪代码,实际上是在汇编器中):
for(outer_loop=0; outer_loop<NO;outer_loop++){
operation #first
operation #second
...
operation #NI-th
}
NI>10^7
较大),则循环的整个内容将无法放入指令高速缓存中,因此必须反复加载,从而使RAM的速度定义了执行所需的时间。例如,对于较大的内部零件,
xorl %eax, %eax
(2个字节)比
xorq %rax, %rax
(3个字节)快33%。
NI
很小,并且整个循环很容易放入指令高速缓存中,则
xorl %eax, %eax
和
xorq %rax, %rax
同样快,并且每个时钟周期可以执行4次。
jmp
指令。对于
jmp
指令,我的测试代码如下:
for(outer_loop=0; outer_loop<NO;outer_loop++){
jmp .L0
.L0: jmp .L1
L1: jmp L2
....
}
NI>10^4
),我测量的值为4.2 ns /
jmp
(相当于从RAM加载的42个字节,或在我的计算机上约为12个时钟周期)。
NI<10^3
),我测量的是1 ns /
jmp-
指令(大约3个时钟周期,这听起来似乎是合理的-Agner Fog的表显示了2个时钟周期的成本)。
jmp LX
使用2字节
eb 00
编码。
jmp
指令成本高的解释是什么?
sh jmp_test.sh
。
ǸI
值(相对于
NI
= 1000)的每条指令的周期:
|oprations/ NI | 1000 | 2000| 3000| 4000| 5000| 10000|
|---------------------|------|------|------|------|------|------|
|jmp | 1.0 | 1.0 | 1.0 | 1.2 | 1.9 | 3.8|
|jmp+xor | 1.0 | 1.2 | 1.3 | 1.6 | 2.8 | 5.3|
|jmp+cmp+je (jump) | 1.0 | 1.5 | 4.0 | 4.4 | 5.5 | 5.5|
|jmp+cmp+je (no jump) | 1.0 | 1.2 | 1.3 | 1.5 | 3.8 | 7.6|
jmp
指令,(尚未确定)资源变得稀缺,这会导致
ǸI
大于4000的性能下降。
xor
之类的指令共享-如果
NI
和
jmp
相互执行,则大约4000的
xor
仍会导致性能下降。
je
共享-对于
jmp
+
je
而言,彼此之后,
NI
的资源变得稀缺,大约为2000。
je
根本不跳,则资源再次变得稀缺,因为
NI
大约为4000(第4行)。
jmp
循环之间吞吐量差异的原因。
最佳答案
TL:DR:我当前的猜测是BTB(分支目标缓冲区)条目已用完。见下文。
即使您的jmp
没有操作,CPU也没有额外的晶体管来检测这种特殊情况。它们的处理方式与其他任何jmp
一样,这意味着必须重新启动从新位置提取的指令,从而在管道中产生气泡。
要了解有关跳转及其对流水线CPU的影响的更多信息,Control Hazards in a classic RISC pipeline应该很好地介绍了为何流水线CPU很难分支的原因。阿格纳·福格(Agner Fog)的指南解释了实际的含义,但是我认为应该假设其中的一些背景知识。
您的Intel Broadwell CPU has a uop-cache,用于缓存解码的指令(与32kiB L1 I缓存分开)。
uop缓存的大小为32组8路,每行6 oups,总共1536 uops(如果每行装满6 oups,则效率非常高)。
1536微码介于1000和10000之间。在您进行编辑之前,我预计从慢到快的临界值大约在您的循环中共有1536条指令。直到远远超过1536条指令,它才不会减慢速度,因此我认为我们可以排除uop-cache的影响。这不是我想的那么简单的问题。 :)
从uop缓存(较小的代码大小)而不是x86指令解码器(较大的循环)运行意味着在识别jmp
指令的阶段之前,流水线阶段较少。因此,即使预测正确,我们也可以预期来自不断跳跃的气泡会更小。
从解码器运行可能会给分支带来较大的错误预测损失(例如,可能是20个周期而不是15个周期),但是这些并不是错误预测的分支。
即使CPU不需要预测分支是否被采用,它仍可以使用分支预测资源来预测代码块在解码之前包含分支。
缓存特定代码块中存在分支及其目标地址的事实,可以使前端在实际解码jmp rel32
编码之前开始从分支目标中获取代码。请记住,解码可变长度的x86指令很困难:在解码上一条指令之前,您不知道哪条指令从哪里开始。因此,您不仅可以对指令流进行模式匹配,以在获取指令流后立即查找无条件的跳转/调用。
我当前的理论是,当用完分支目标缓冲区条目时,您的速度会变慢。
另请参见What branch misprediction does the Branch Target Buffer detect?,它有一个很好的答案,并在此Realworldtech thread中进行了讨论。
一个非常重要的观点:BTB根据下一步要提取的块进行预测,而不是根据提取块中特定分支的确切目的地进行预测。因此,不必预测获取块中所有分支的目标,而是the CPU just needs to predict the address of the next fetch.
是的,当运行诸如xor-zeroing之类的非常高吞吐量的东西时,内存带宽可能会成为瓶颈,但是您使用jmp
遇到了另一个瓶颈。 CPU将有时间从内存中获取42B,但这不是它的工作。预取可以很容易地保持每3个时钟2个字节的速度,因此L1 I高速缓存未命中应该接近于零。
在具有/不具有REX测试的xor
中,如果您使用足够大的循环进行测试以不适合L3缓存,则实际上主内存带宽可能一直是瓶颈。在〜3GHz的CPU上,每个周期消耗4 * 2B,这大约可以最大达到DDR3-1600MHz的25GB / s的速度。不过,即使是L3高速缓存,其速度也足以使其每个周期保持4 * 3B的速度。
有趣的是主内存带宽是瓶颈。最初,我猜想解码(以16字节为一组)将成为3字节XOR的瓶颈,但我想它们足够小。
还要注意,以核心时钟周期衡量时间更为正常。但是,我猜想,当您查看内存时,以ns为单位的测量非常有用,因为低时钟速度可节省功耗,从而改变了核心时钟速度与内存速度的比值。 (即,在最低CPU时钟速度下,内存瓶颈问题不大。)
要以时钟周期进行基准测试,请使用perf stat ./a.out
。还有其他有用的性能计数器,这些对于尝试了解性能特征至关重要。
有关Core2的性能计数器结果(每个jmp 8个周期)和一些未知的微体系结构(每个jmp约为10c),请参见x86-64 Relative jmp performance。
即使在或多或少的白盒条件下,现代CPU性能特征的细节也很难理解(请阅读英特尔的优化手册,以及他们发布的有关CPU内部的内容)。如果您坚持要进行黑盒测试,而您却不阅读有关新CPU设计的arstechnica文章,或者诸如David Kanter的Haswell microarch overview之类的更详细的文章,则常常会早早陷入困境。我之前链接的Sandybridge文章。
如果尽早地被卡住并且经常没事,并且您在找乐子,那么请务必继续做您正在做的事情。但是,如果您不知道这些详细信息(例如在这种情况下),那么人们就很难回答您的问题。 :/例如我对这个答案的第一个版本假定您已经阅读了足够的知识,以了解uop缓存是什么。
关于performance - 慢速jmp指令,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38811901/
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 8年前关闭。 Improve t
暂时忘记能力的定义,只关注能力的“检查”(使用“授权!”),我看到 CanCan 添加了大约 400 毫秒,用于简单地检查用户是否具有特定的能力主题/模型。 这是预期的吗(我假设不是)?或者,有没有可
我正在阅读有关 Swift 的教程 ( http://www.raywenderlich.com/74438/swift-tutorial-a-quick-start ),它预定义为不显式设置类型,因
这主要是由于对 SQL 问题的回答。由于性能原因,有意省略了 UDF 和子查询。我没有包括可靠性并不是说它应该被视为理所当然,但代码必须工作。 性能永远是第一位的吗?提供了许多以性能为主要优先事项的答
我已经编写了一个简单的测试平台来测量三种阶乘实现的性能:基于循环的,非尾递归的和尾递归的。 Surprisingly to me the worst performant was the loop o
我已将 ui-performance 插件应用到我的应用程序中。不幸的是,在开发模式下运行应用程序时它似乎不起作用。例如,我的 javascript 导入是用“vnull”版本呈现的。 例如 不会
我有一个我操作的 F# 引用(我在各处添加对象池以回收经常创建和删除的短期对象)。我想运行结果报价;现在我使用了 F# PowerPack,它提供了将引用转换为表达式树和委托(delegate)的方法
我正在尝试在 Spark 服务器上运行 SparklyR 库中的机器学习算法。 1 个簇 8 核 24G内存 Ubuntu 16.04 星火2.2 独立配置 1名师傅/2名 worker 每个执行器的
我有一个数据库(准确地说是在 postgres 上运行),具有以下结构: user1 (schema) | - cars (table) - airplanes (table, again) .
我的应用程序在我的 iPad 上运行。但它的表现非常糟糕——我的速度低于 15fps。谁能帮我优化一下? 它基本上是一个轮子(派生自 UIView),包含 12 个按钮(派生自 UIControl)。
在完成“Scala 中的函数式编程原则”@coursera 类(class)第 3 周的作业时,我发现当我实现视频类(class)中所示的函数联合时: override def union(tha
我正在重构我的一个 Controller 以使其成为一项服务,我想知道不将整个服务容器注入(inject)我的 Controller 是否会对性能产生影响。 这样效率更高吗: innova.path.
我有一个要显示的内容很大的文件。例如在显示用户配置文件时, 中的每个 EL 表达式需要一个 userId 作为 bean 的参数,该参数取自 session 上下文。我在 xhtml 文件中将这个 u
我非常了解 mipmapping。我不明白(在硬件/驱动程序级别)是 mipmapping 如何提高应用程序的性能(至少这是经常声称的)。在执行片段着色器之前,驱动程序不知道要访问哪个 mipmap
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: What's the (hidden) cost of lazy val? (Scala) Scala 允许定义惰
一些文章建议现在 build() 包含在 perform() 本身中,而其他人则建议当要链接多个操作时使用 build().perform()一起。 最佳答案 build() 包含在 perform(
Postgres docs说 For best optimization results, you should label your functions with the strictest vol
阅读Zero-cost abstractions看着 Introduction to rust: a low-level language with high-level abstractions我尝
我想在 MQ 服务器上部署 SSL,但我想知道我当前的 CPU 容量是否支持 SSL。 (我没有预算增加 CPU 内核和 MQ PVU 的数量) 我的规范: Windows 2003 服务器 SP2,
因此,我在 Chrome 开发者工具 的性能 选项卡内的时间 部分成功地监控了我的 React Native 应用程序的性能。 突然在应用程序的特定重新加载时,Timings 标签丢失。 我已尝试重置
我是一名优秀的程序员,十分优秀!