说到检测CPU的速度,一般是测试在单位时间内运算的指令条数,但用这种方法有太大的局限性,由于受到很多因素的影响,准确度比较低,特别是在Windows环境下,你不知道在你的程序外别的程序占用了多少的时间片。其实,在586及以上档次处理器中,已经有了一条专用的指令来测试主频,那就是
RDTSC指令,意思是读取时间标记计数器(Read Time-Stamp Counter),Time-stamp counter 是处理器内部的一个64位的MSR
(model specific register),它每个时钟增加一个记数。在处理器复位的时候,初始值为0,RDTSC 指令把 TSC的值低32位装入EAX中,高32位装入EDX中。如果CPU的主频是200MHz,那么在一秒钟内,TSC的值增加
200,000,000 次。所以在计算的时候,把两次的TSC差值除以两次的时间差值就是CPU的主频。
程序的结构如下: 初始化的时候设置一个定时器,定时时间为1秒,然后在定时器消息中利用 RDTSC 取得
TSC计数,再和上次保留的值相减,然后除以时间差即可。
源程序:
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Programmed by 罗云彬, bigluo@telekbird.com.cn
; Website: http://asm.yeah.net
; LuoYunBin's Win32 ASM page (罗云彬的编程乐园)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 版本信息
; CPU 频率 - 利用586指令 rdtsc 计算CPU的频率
; V1.0 ------ 2000年6月21日
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.586
.MODEL FLAT, STDCALL
option casemap :none ; case sensitive
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
INCLUDE WINDOWS.INC
INCLUDE USER32.INC
INCLUDE KERNEL32.INC
INCLUDE COMCTL32.INC
INCLUDE COMDLG32.INC
INCLUDELIB USER32.LIB
INCLUDELIB KERNEL32.LIB
INCLUDELIB COMCTL32.LIB
INCLUDELIB COMDLG32.LIB
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 数据
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
DLG_MAIN EQU 1000
ID_SPEED EQU 1001
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.DATA?
DWTICKCOUNT DD ?
DWTSC DD ?,?
HINSTANCE DD ?
SZBUFFER DB 256 DUP (?)
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 子程序声明
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcDlgMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
.DATA
SZSPEED DB "你的CPU主频为 %D MHZ",0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.CODE
INCLUDE WIN.ASM
;********************************************************************
_PROCDLGMAIN PROC USES EBX EDI ESI, \
hWnd:DWORD,wMsg:DWORD,wParam:DWORD,lParam:DWORD
LOCAL @STPOINT:POINT
LOCAL @HWINDOW
MOV EAX,WMSG
.IF EAX == WM_CLOSE
INVOKE ENDDIALOG,HWND,NULL
INVOKE KILLTIMER,HWND,1
.ELSEIF EAX == WM_INITDIALOG
INVOKE _CENTERWINDOW,HWND
INVOKE GETTICKCOUNT ;TSC 初始值
MOV DWTICKCOUNT,EAX
RDTSC
MOV DWTSC,EAX
MOV DWTSC+4,EDX
INVOKE SETTIMER,HWND,1,1000,NULL
.ELSEIF EAX == WM_TIMER
INVOKE GETTICKCOUNT
PUSH EAX
SUB EAX,DWTICKCOUNT
POP DWTICKCOUNT
PUSH EAX
RDTSC
PUSH EDX
PUSH EAX
SUB EAX,DWTSC
SBB EDX,DWTSC+4
POP DWTSC
POP DWTSC+4
MOV ECX,1000000
DIV ECX ;除以1Mhz=1000000hz
.IF EDX >= 500000H ;四舍五入
INC EAX
.ENDIF
MOV ECX,1000
MUL ECX ;1秒=1000毫秒
POP ECX ;pop出经过的毫秒数
DIV ECX
INVOKE WSPRINTF,OFFSET SZBUFFER,OFFSET SZSPEED,EAX
INVOKE SENDDLGITEMMESSAGE,HWND,ID_SPEED,\
WM_SETTEXT,0,offset szBuffer
.ELSE
;********************************************************************
; 注意:对话框的消息处理后,要返回 TRUE,对没有处理的消息
; 要返回 FALSE
;********************************************************************
MOV EAX,FALSE
RET
.ENDIF
MOV EAX,TRUE
RET
_PROCDLGMAIN ENDP
;********************************************************************
START:
INVOKE GETMODULEHANDLE,NULL
MOV HINSTANCE,EAX
INVOKE DIALOGBOXPARAM,HINSTANCE,DLG_MAIN,NULL,OFFSET _PROCDLGMAIN,0
INVOKE EXITPROCESS,NULL
END START