假设我在汇编中有两个相同算法的实现。我想通过检查一个更快的两个代码段来了解。
我认为可以考虑的参数是:操作码数量,分支数量,功能帧数量。
我的问题是:
- 我可以假设每个操作码执行一个周期吗?
- 破坏管道的分支的开销是多少?
- 调用函数有什么影响和开销?
- ARM和x86之间的分析是否存在差异?
醇>
这个问题是理论性的,因为我有两个实现;一个130指令长,一个指令长184个。
我想知道130条指令长片段是否比184条指令长实现速度更快是否正确?
答案 0 :(得分:11)
不想轻浮,答案是
- 没有
- 取决于您的硬件
- 取决于您的硬件
- 是
醇>
你真的需要在你的目标硬件上测试一些东西,或者有一台能够完全理解你的硬件的模拟器,以便以你想要的方式回答你的问题......
对于问题的最后一部分,您需要定义“更好”......更好。
答案 1 :(得分:8)
由于您询问的是Cortex A9,data sheet的指令周期计数在附录B 中。这些计数通常假设内存总线足够快以保持CPU忙。实际上,这种情况很少发生。许多视频/音频算法将在访问内存方面取得巨大成功。
当然,如果您想要精确计数,则不能假设这一点。但是,如果您要决定选择哪种算法,可以通过查看内部循环中的说明来了解最佳算法。在这里,您的cache
应该允许代码按照数据表中的指令计数执行。如果计数接近,那么您可能需要查看每条指令。加载/存储更加昂贵并且通常是倍数等。一些算法,特别是加密算法,通过使用不能很好地映射到C
的汇编程序将获得巨大的胜利。例如,clz
,ror
,使用进位进行多字算术等。
查看附录B ,或任何数据表中有处理器周期数。对于ARM926,它大约是3个周期。编译器只在一行中生成两个条件操作码以避免分支,否则它会分支。如果算法很大,分支可能会破坏缓存。 硬答案取决于您的CPU,缓存和内存。根据Cortex A9数据表(B.5),固定分支只有一个周期开销。
这与分支开销非常相似。但是,编译器也会产生影响。 noted by Jim 是否缓存对齐函数。编译器是否执行叶函数优化等。对于现代gcc
版本,如果所有函数都是静态的,编译器通常会在有利的时候内联。如果算法特别大,则寄存器溢出可能是有利的。但是,以130/184指令为例,这似乎不太可能。编译器选项显然会影响开销。您可以使用objdump -S
检查序言/结尾,然后确定硬件的周期数。
当然,循环计数存在技术差异。 CISC
x86还具有变量指令大小。这使分析复杂化。它在ARM上稍微容易一些。
通常情况下,您想要停放球,然后使用分析器实际运行它们。估计可以帮助指导算法的开发。硬件的循环/内存调整等。像instruction emulation
,page
或alignment faults
之类的东西可能占主导地位,并使所有循环计数分析无意义。如果算法在user space
中,则per-emption可以否定从运行到运行的缓存获胜。一个算法可能在一个小负载系统中工作得更好,而另一个算法在更高负载下工作得更好。
有关获取周期计数的一些并发症,请参阅post-process objdump。基本上,典型的CPU是几个阶段(管道线),不同的条件可能导致停顿。随着CPU变得越来越复杂,管道通常会变得更长,这意味着有更多的条件或阶段会停滞。但是,循环计数估计值可以帮助指导算法的开发和评估它们。 内存时序或分支预测等内容同样重要,具体取决于算法。即,循环计数并非完全没用,但它们也不完整。分析应确认实际算法时间。如果它们分歧,指令重新排序,预取和其他技术可能会使它们更接近。 循环计数和活动分析差异的事实本身就是有用的。
答案 2 :(得分:3)
确实130指令代码比184指令代码快,这是绝对不正确的。 1000个指令的运行速度比100快,非常容易,反之亦然。
1我可以假设每个操作码执行一个周期吗?
首先查看广告中的mips / mhz,虽然营销号码可以大致了解可能的情况。如果数字大于1,则每个时钟可能有多个指令。
2分支破坏管道的开销是多少?
在任何一个系统上的任何地方,绝对没有影响到非常戏剧性的影响。一个时钟到几百个是潜在的惩罚。
3调用函数有什么影响和开销?
在很大程度上取决于函数和调用函数的函数。根据调用约定,您可能必须将寄存器保存到堆栈,或重新排列寄存器的内容以准备要调用的函数的参数。如果按值传递结构,则可能需要在堆栈上创建结构的副本,结构越大,副本越大。一旦在功能中,可能需要准备堆栈帧等,涉及许多因素。这个问题和答案也独立于平台。
4 ARM和x86之间的分析是否存在差异?
是和否,两个系统都使用流水线,分支预测等所有现代技巧来保持mips / mhz。 ARM将提供比m86更好的mips mips,x86是可变指令长度可能会为每个单元缓存提供更多指令。如何分析缓存,分析系统端的内存和外围系统大致相同。根据您正在分析的方面,指令和核心的比较是相似和不同的。手臂没有微编码,x86可能是这样你真的没有看到有多少寄存器,这样的事情。与此同时,你可以用手臂更好地查看内存系统,因为它们通常不是片上系统。根据您购买的ARM芯片,您可能会失去芯片边界的大量可见性,例如,可能看不到所有内存和外设总线。 (x86正在通过将pcie放在芯片上来改变它,例如)在皮质中的某些东西 - 你提到的类你将拥有类似的芯片可视性边缘,因为那些将使用更大/更便宜的基于dram的存储器芯片而非微控制器像片上资源一样。
最后一句问题:
“而且我想知道130条指令长片段是否比184条指令长实现速度快?”
说130指令片段比184指令片段快,绝对不是正确的。它可能会更快,它可能会更慢,它可能会大致相同。有了更多的信息,我们可能会做出相当不错的陈述,或者它可能仍然是非确定性的。很容易选择执行速度超过1000条指令的100条指令,同样很容易选择执行速度超过100条指令的1000条指令(即使我没有添加分支也没有循环,只是线性执行)
答案 3 :(得分:3)
您的问题几乎毫无意义:可能取决于您的输入。
大多数CPU具有类似于分支错误预测惩罚的东西(例如,传统的ARM在任何采用的分支上丢弃指令获取/解码,IIRC)。 ARM和x86还允许条件执行,可以比分支更快。如果其中任何一个依赖于输入数据,则不同的输入将遵循不同的代码路径。
也许一个版本大量使用条件执行,这在条件为假时是浪费的。也许另一个是使用一些分析信息编译的,这些信息不对特定情况执行任何分支(除了最后的返回)。编译器可以采用相同的源并产生“优化”输出的原因有很多,这对于一个输入更快,而对另一个输入更慢。
许多优化都具有这一特性 - 例如,将循环的开始与16个字节对齐有助于某些处理器,但是当循环仅执行一次时则不行。
答案 4 :(得分:2)
有些教科书从Cortex
™
-A Series Programmer’s Guide,chapter 17
回答了这个问题。
虽然可以在您正在使用的处理器的技术参考手册(TRM)中找到循环时序信息,但很难计算出即使是一小部分代码执行也需要多少个循环。指令通过管道的移动取决于周围指令的进度,并且可能受到存储器系统的显着影响 活动。在缓存中丢失的待处理加载或指令提取可以使代码停顿数十个周期。标准数据处理指令(逻辑和算术)只需要执行一个或两个周期,但这并不能给出完整的图像。相反,我们必须使用分析工具或处理器内置的系统性能监视器来提取有关性能的有用信息。
同时在17.4 Cortex-A9 micro-architecture optimizations
下阅读,非常非常回答您的问题。