如何检测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




(C) Copyright by LuoYunBin's Win32 ASM Page,http://asm.yeah.net