我正在为 Cortex-M4 编写一些汇编代码,特别是 STM32F4DISCOVERY 套件中的 STM32F407VG。
该代码对性能极其敏感,因此我希望从中挤出最后一个周期。我对其进行了基准测试(使用 Cortex-M4 中提供的 DWT 周期计数器),对于特定大小的输入,它以 1494 个周期运行。代码从闪存运行,CPU 降频至 24 MHz,以确保对闪存进行真正的零等待状态访问(禁用 ART 加速器)。对 DWT 周期计数器的两次连续读取进行基准测试会产生一个周期,因此这是与基准测试相关的唯一开销。
该代码仅从闪存读取 5 个常量 32 位字(如果从闪存读取指令和数据,可能会导致总线矩阵争用);所有其他数据存储器访问都是从 RAM 进行或到 RAM 进行的。我确保所有分支目标都是 32 位对齐的,并手动.W向某些指令添加后缀以消除所有指令,除了两个 16 位但不是 32 位对齐的 32 位指令——其中之一没有即使运行这个输入大小,第二条是POP函数的最终指令,它显然不是在循环中运行。请注意,大多数指令使用 32 位编码:实际上,平均指令长度为 3.74 字节。
我还制作了一个电子表格,记录了代码中的每一条指令,它们在循环内运行了多少次,甚至还记录了每个分支是否被采用,因为这会影响给定指令需要的周期数。我阅读了Cortex-M4 技术参考手册(TRM) 来获取每条指令的周期计数,并始终使用最保守的估计:当一条指令取决于管道刷新的成本时,我假设它最多需要 3 个周期;此外,我假设了所有加载和存储的最坏情况,尽管 TRM 第 3.3.2 节中讨论的许多特殊情况实际上可能会减少这些计数。我的电子表格包含 DWT 周期计数器两次读取之间每条指令的成本。
因此,我非常惊讶地发现我的电子表格预测代码应该在 1268 个周期内运行(回想一下实际性能是 1494 个周期)。我无法解释为什么代码的运行速度比根据指令时序假定的最坏情况慢 18%。即使完全展开代码的主循环(应负责大约 3/4 的执行时间)也只能将其减少到 1429 个周期,并且快速调整电子表格表明此展开的版本应在 1186 个周期内运行。
有趣的是,同一算法的完全展开、仔细调整的 C 版本运行了 1309 个周期。它总共有 1013 条指令,而我的汇编代码的完全展开版本有 930 条指令。在这两种情况下,都有一些代码处理未由用于基准测试的特定输入执行的情况,但就这些未使用的代码而言,C 版本和汇编版本之间应该没有显着差异。最后,C …
在英特尔优化手册似乎对存储缓冲区的数量存在于处理器的许多地方,但谈判没有谈存储缓冲区的大小.这是公共信息还是商店缓冲区的大小保留为微架构细节?
我正在研究的处理器主要是Broadwell和Skylake,但其他人的信息也不错.
另外,存储缓冲区究竟做了什么?