测量执行单个指令的时间

有没有办法使用C或汇编程序甚至C#来准确衡量执行ADD指令所需的时间?

是的,有点,但它是非平凡的,并产生几乎毫无意义的结果,至少在最合理的现代处理器上。

在相对较慢的处理器上(例如,通过Intel系列中的原始Pentium,在大多数小型嵌入式处理器上仍然如此),您只需查看处理器的数据表,它(通常)会告诉您预期会有多少时钟周期。 快速,简单,轻松。

在现代台式机(例如Pentium Pro或更新版)上,生活并不那么简单。 这些CPU一次可以执行许多指令,只要它们之间没有任何依赖关系,就可以不按顺序执行它们。 这意味着单个指令所用时间的整个概念几乎变得毫无意义。 执行一条指令所花费的时间可以并且将取决于它周围的指令。

也就是说,是的,如果你真的想要,你可以(通常 – 取决于处理器)测量某些东西,尽管它可以确切地说明它究竟意味着什么。 即使得到这样的结果只是接近无意义而不是完全没有意义,但这并不是微不足道的。 例如,在Intel或AMD芯片上,您可以使用RDTSC进行定时测量。 遗憾的是,这可以如上所述不按顺序执行。 要获得有意义的结果,您需要通过无法执行的指令(“序列化指令”)将其包围。 最常见的选择是CPUID ,因为它是“用户模式”(即第3环)程序可用的少数序列化指令之一。 这增加了一点点扭曲:正如英特尔所记录的那样,处理器执行CPUID的前几次,它可能需要比后续时间更长的时间。 因此,他们建议您在使用序列化时序之前执行三次 。 因此,一般序列运行如下:

 .align 16 CPUID CPUID CPUID RDTSC ; sequence under test Add eax, ebx ; end of sequence under test CPUID RDTSC 

然后将其与执行相同的结果进行比较,但删除了测试中的序列。 当然,这遗漏了很多细节 – 至少你需要:

  1. 在每个CPUID之前正确设置寄存器
  2. 在第一个RDTSC之后保存EAX:EDX中的值
  3. 从第一个RDTSC中减去第二个RDTSC的结果

还要注意我插入的“对齐”指令 – 指令对齐也会影响时序,特别是如果涉及到一个循环。

构造一个执行1000万次的循环,循环体中没有任何东西,时间也是如此。 将该时间保留为循环所需的开销。

然后再次执行相同的循环,这次使用正文中的测试代码。 此循环的时间减去开销(来自空循环的情况)是由于您测试的代码重复1000万次而导致的时间。 所以,除以迭代次数。

显然,这种方法需要根据迭代次数进行调整。 如果您测量的内容很小,就像单个指令一样,您甚至可能希望运行超过十亿次迭代。 如果它是一大堆代码,那么几十个代码就足够了。

在单个汇编指令的情况下,如果您熟悉内联汇编,汇编程序可能是正确的工作工具,或者可能是C。 其他人已经发布了更优雅的解决方案,用于如何获得没有重复的测量,但重复技术始终可用,例如,嵌入式处理器没有其他人提到的好的时序指令。

但请注意,在现代流水线处理器上,指令级并行可能会使您的结果混乱。 因为一次有多条指令通过执行流水线运行,所以给定指令的N次重复不再是单个指令的N倍。

好的,如果您使用的是Windows,Linux,Unix,MacOS,AmigaOS等操作系统,以及其他已经在您的计算机上运行的许多进程会影响性能的问题,您将遇到的问题。 计算指令实际时间的唯一真正方法是拆卸主板并使用外部硬件测试每个组件。 这取决于您是否绝对想要自己完成此操作,或者只是了解处理器的典型修订版实际运行的速度有多快。 英特尔和摩托罗拉等公司在发布之前对其芯片进行了广泛的测试,这些结果可供公众使用。 所有你需要做的就是问他们,他们会给你发送一张免费的CD-ROM(可能是DVD – 无意义的迂腐),并附上结果。 您可以自己做,但要注意,特别是英特尔处理器包含许多不再需要的冗余指令,更不用说必要了。 这将花费你很多时间,但我完全可以看到这样做的乐趣。 PS。 如果它纯粹是为了帮助你将自己机器的硬件推向个人项目中的理论最大值,那么Just Jeff的答案非常适合在真实条件下生成整齐的指令速度平均值。

不,但您可以根据添加指令所需的时钟周期数乘以CPU的时钟速率来计算它。 ADD的不同类型的参数可能导致更多或更少的循环,但是对于给定的参数列表,指令总是需要相同的循环数来完成。

那说,你为什么关心?