30. 速度测试

优质
小牛编辑
122浏览
2023-12-01

奔腾家族的处理器内部有一个64位的时钟计数器,通过RDTSC(read time stamp
counter,读时间戳计数器)指令可以把它的值读到EDX:EAX寄存器中。 这对于确切测试一块代码用掉的时钟数十分有用。

下面的代码对测试一块代码花去的时钟数很有用。
程序执行要测的代码片段,测试10次,以10个时钟为一个单位,保存用掉的单位数。 这段代码可以在PPlain和PMMX上的16位或32位模式下使用:

;************
PPlain和PMMX上的测试程序: ********************

ITER EQU 10 ; 叠代次数

OVERHEAD EQU 15 ; 对于PPlain是15,对于PMMX是17

RDTSC MACRO ; 定义RDTSC指令

DB 0FH,31H

ENDM

;************ 数据段: ********************

。DATA ; 数据段

ALIGN 4

COUNTER DD 0 ; 循环计数器

TICS DD 0 ;
存储时钟数的临时变量

RESULTLIST DD ITER DUP (0) ; 存储结果的数组

;************ 代码段: ********************

。CODE ; 代码段

BEGIN: MOV [COUNTER],0
; 循环计数器复位

TESTLOOP: ; 循环测试

;************ 在这里做一些任意的初始化工作: ********************

FINIT

;************ 初始化结束
********************

RDTSC ; 读时钟计数器

MOV [TICS],EAX ; 保存计数值

CLD
; 无法配对的填充指令

REPT   8

NOP ;
放8个NOP避免影响后面要测试的代码

ENDM

;************ 这里放置要测试的代码:
********************

FLDPI ; 这只是一个例子

FSQRT

RCR EBX,10

FSTP ST

;*****************
要测试的代码结束 *******************

CLC ;
无法配对的,带“阴影”的填充指令,使RDTSC的前缀在其“阴影”里解码

RDTSC ;
再次读计数器

SUB EAX,[TICS] ; 计算两次的差

SUB EAX,OVERHEAD ; 减去填充指令等用掉的时钟数

MOV EDX,[COUNTER] ; 循环计数器

MOV [RESULTLIST][EDX],EAX ; 结果存入数组

ADD EDX,TYPE RESULTLIST ; 增加计数器

MOV [COUNTER],EDX ; 保存计数器

CMP EDX,ITER * (TYPE RESULTLIST)

JB TESTLOOP ; 重复叠代过程

;
这里还要写一些把值从RESULTLIST中读出的代码

在PPlain上,在被测代码的前面和后面的填充指令是为了每次叠代都能获得一致的结果。
CLD是一条无法配对的指令,插在这里是为了保证第一次叠代时指令的配对情况与后面的叠代相同。
在PPlain上,插入8个NOP的目的是避免被测代码的任何前缀的解码时间与前面指令重叠(避免阴影效应)。
这里使用了单字节指令,使后续叠代的配对情况与第一次叠代时相同。
在PPlain上,在被测代码之后的CLC指令是一条无法配对的指令,带有“阴影”,使RDTSC的0FH前缀的解码时间与CLC的执行时间重叠(在其阴影里解码),这样RDTSC就与被测代码独立,不会在被测代码的阴影中解码了。

在PMMX上,如果希望FIFO(先进先出)的指令缓存为空,你可以在指令前先插入XOR EAX,EAX /
CPUID来检测;如果希望FIFO的缓存是满的,那么就插入一些耗时的指令(比如,CLI或AAD)(CPUID没有阴影,即后续指令前缀的解码无法在CPUID执行时重叠进行)。

在PPro,PII和PIII上,在每个RDTSC之前、之后你必须插入XOR EAX,EAX / CPUID
以避免RDTSC与任何指令并行执行,并且不要写填充指令(CPUID是序列化指令,即它在进行前会等待所有未完的操作结束,且清洗流水线。
故将它用于测试目的很合适)。

在PPlain和PMMX上,RDTSC指令不能在虚拟模式下执行。
故倘若想运行DOS程序,则必须在实模式下运行(在重启机器时按F8,选择"safe mode command prompt only" 或 "bypass
startup files")。

整个测试程序可以到 www.agner.org/assem/
下载。

奔腾处理器还带有一些专门用于监控性能的计数器。
可以为诸如cache失效,未对齐操作,各种延迟等事件计数。 性能监控计数器的详细介绍就略过了,可以在“Intel架构下的软件开发者手册”("Intel
Architecture Software Developer's Manual"),vol.3,附录A找到。