ITEEDU

如何检测CPU的主频

概述:

说到检测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