通常,程序员发现用测量执行时间的方法来比较一段代码与另一段代码执行的性能是很有用的。Microsoft Windows API 为此提供了必要的工具,lrvine32 库中的 GetMseconds 过程可使其变得更加方便使用。该过程获取系统自午夜过后经过的毫秒数。
在下面的代码示例中,首先调用 GetMseconds,这样就可以记录系统开始时间。然后调用想要测量其执行时间的过程 (FirstProcedureToTest)。最后,再次调用 GetMseconds,计算开始时间和当前毫秒数的差值:
- .data
- startTime DWORD ?
- procTime1 DWORD ?
- procTime2 DWORD ?
- .code
- call GetMseconds ;获得开始时间
- mov startTime, eax
- .
- call FirstProcedureToTest
- .
- call GetMseconds ;获得结束时间
- sub eax, startTime ;计算执行花费的时间
- mov procTime1, eax ;保存执行花费的时间
当然,两次调用 GetMseconds 会消耗一点执行时间。但是在衡量两个代码实现的性能时间之比时,这点开销是微不足道的。现在,调用另一个被测试的过程,并保存其执行时间 (procTime2):
- call GetMseconds ;获得开始时间
- mov startTime, eax
- .
- call SecondProcedureToTest
- .
- call GetMseconds ;获得结束时间
- sub eax, startTime ;计算执行花费的时间
- mov procTime2, eax ;保存执行花费的时间
则 procTime1 和 procTime2 的比值就可以表示这两个过程的相对性能。
对老的 x86 处理器来说,用移位操作实现乘法和用 MUL、IMUL 指令实现乘法之间有着明显的性能差异。可以用 GetMseconds 程比较这两种类型乘法的执行时间。下面的两个过程重复执行乘法,用常量 LOOP_COUNT 决定重复的次数:
- mult_by_shifting PROC
- ;
- ;用 SHL 执行 EAX 乘以 36,执行次数为LOOP_COUNT
- mov ecx, LOOP_COUNT
- L1: push eax ;保存原始 EAX
- mov ebx, eax
- shl eax, 5
- shl ebx, 2
- add eax, ebx
- pop eax ;恢复 EAX
- loop LI
- ret
- mult_by_shifting ENDP
- mult_by_MUL PROC
- ;
- ;用MUL执行EAX乘以36,执行次数为LOOP_COUNT
- mov ecx, LOOP_COUNT
- LI: push eax ;保存原始 EAX
- mov ebx, 36
- mul ebx
- pop eax ;恢复 EAX
- loop L1
- ret
- mult_by_MUL ENDP
下述代码调用 multi_by_shifting,并显示计时结果。
- .data
- LOOP_COUNT = 0FFFFFFFFh
- .data
- intval DWORD 5
- startTime DWORD ?
- .code
- main PROC
- call GetMseconds ; 获取开始时间
- mov startTime,eax
- mov eax,intval ; 开始乘法
- call mult_by_shifting
- call GetMseconds ; 获取结束时间
- sub eax,startTime
- call WriteDec ; 显示乘法执行花费的时间
用同样的方法调用 mult_by_MUL,在传统的 4GHz 奔腾 4 处理器上运行的结果为:SHL 方法执行时间是 6.078 秒,MUL 方法执行时间是 20.718 秒。也就是说,使用 MUL 指令速度会慢 2.41 倍。
但是,在近期的处理器上运行同样的程序,调用两个函数的时间是完全一样的。这个例子说明,Intel 在近期的处理器上已经设法大大地优化了 MUL 和 IMUL 指令。