我正在编写代码来比较不同版本函数的执行时间。 我需要帮助来理解我观察到的机器行为。
我计时的代码执行一些数学计算。它主要受 CPU 限制。我的意思是这些函数只访问嵌入在可执行文件中的数据。因此,不需要磁盘或任何其他外部资源。
我这样计时功能(这是在 Windows 上):
rdtscp
lfence
shl rdx,32
lea r15,[rdx+rax] ; r15 = ticks before the function is entered
mov rcx,rbp ; the only argument to the function
call [r13] ; call the function being timed
mfence
rdtscp
lfence
shl rdx,32
lea rbx,[rdx+rax] ; rbx = ticks right after the timed function
sub rbx,r15
mov [r12+r14*4],ebx ; store ticks delta
因为我预计一开始处理器没有达到速度,所以我会继续丢弃我得到的滴答样本,只要它们的值在下降(我相信这意味着 CPU 正在加快速度)。当我得到一个等于或大于前一个样本的样本时,我预计 CPU 已达到其最大速度。我保留了那个样本和之前的(较小的)样本,从那时起我收集了另外 18 个样本,总共 20 个。
我的第一个问题是:只要 CPU 加速,我不应该期望看到时序值下降,并且从那时起看到 EQUAL 时序吗?当然,可能会触发 IRQ,(不太可能:)可能会发生上下文切换,其他一些进程可能会破坏我的缓存,等等。但是如果发生任何这种情况,我不应该看到一系列相等的时间紧随其后长钉?唉,那不是我看到的! 这是一个例子:
Discarded 7 initial ticks:
34971 4908 4189 3759 3603 3483 3432
Unordered retained ticks:
3370 3431 3388 3387 3388 3388 3387 3374 3373 3373 3388 3388 3387 3388 3387 3388 3388 3387 3388 3388 3387 3388 3387 3374 3373 3373 3388 3388 3387 3388 3387 3388 3388 3387 3388 3388 3387 3388 3387 3374 3373 3373 3388 3388 3387 3388 3388 3387 3388 3387
我对用一个刻度分隔的值没有问题,比如 3387 和 3388,或者 3373 和 3374。这是正常的抖动。但为什么 3387/3388 之后应该是 3373/3374 然后回到更高的值呢?绝对没有中断 14 ticks 来搞砸事情。
但是主要的问题来自这个观察。在上面的示例中,最常见的测量值是 3388(或者,相同的是:3387)。
但是当我多次重复测试时,我观察到的最常见的值是(按照观察到的顺序):
3350、3312、3310、3295、3286、3334、3440、3344、3300、3311、3306、3331
这些值中的最大值和最小值之间存在 4% 的差异。为什么一个功能的时间应该如此不准确?为什么一个使用完全相同数据、相同资源的函数会像那样改变它的执行时间?
让我困惑的不是我测量的时间不同。如果在一个样本和下一个样本之间我能看到 4% 的差异,我可以接受硬件具有这种分辨率。
但是,为什么在特定的运行中,绝大多数时间应该是 3350,而在下一次运行中,大多数时间是 3312?
我渴望对此有所了解,以帮助我决定如何最好地比较不同的执行时间。
非常感谢。