CPU Speed mit Inline Assembler auslesen?



  • Hi,

    ich code einen C++ Kernel der auch soweit läuft, nun will ich beim Booten (wenn man das so nennen darf *g*) den CPU Speed ausgeben.

    Weis einer wie das geht? Achja, arbeitsspeicher wäre auch sehr hilfreich wenn mir einer sagen könnte wie das geht 🙂

    Schon mal ein dickes Danke im voraus 🙂



  • haste echtzeituhr oder sonsigen definierten timer und rdtsc, dann gehts schon sehr gut.



  • Wegen Speicher: Guck dir mal den Int 11h und den Int 15h Fnkt. 88h an. Ersteres liefert den Speicher unter 1 MB, zweiteres den über 1 MB. Wobei letzteres scheinbar nur maximal 64 MB ermitteln kann, da es die Speichergröße in KB in AX angibt...



  • Diesen Code habe ich mal vor einiger Zeit im Netz gefunden. Man kann den CPU-Speed und CPU-Type ermitteln. Der Code ist für Visual C++ 6, sollte sich aber auch an andere Compiler anpassen lassen. Soweit vorhanden ist die Quelle im Header, dieser Code stammt nicht aus meiner Feder. Da das hier grossenteils Assembler ist und die Frage hierzu passte bitte ich um Entschuldigung für dieses Monster hier - ausgerechnet im Assembler-Forum. Die Assemblerteile sollten sich ja auch wieder verwenden lassen. 😉

    Beispiel wie das verwendet wird kommt weiter unten.

    // CpuId.h: interface for the CCpuId class.
    //
    // Copyright (c) 1998 by Bill Oatman.  
    // All rights reserved.
    // http://www.netacc.net/~waterbry/cpuid/cpuid.htm
    //
    // Basic CPU and speed detection routines 
    // Copyright (c) 1995, Intel Corporation.  All rights reserved.
    //////////////////////////////////////////////////////////////////////
    
    #ifndef _CPUID_H
    #define _CPUID_H
    
    //nicht MFC: Anstelle der CString einfach string der STL oder char[] verwenden.
    
    class CCpuId  
    {
    public:
    	static void GetCpuSpeed(CString *CpuSpeed);
    	static void GetCpuId(CString *CpuIdStr);
    	CCpuId();
    	virtual ~CCpuId();
    
    };
    
    #endif //_CPUID_H
    

    Die Implementierung:

    // CpuId.cpp: implementation of the CCpuId class.
    //
    // Copyright (c) 1998 by Bill Oatman.  
    // All rights reserved.
    // http://www.netacc.net/~waterbry/cpuid/cpuid.htm
    //
    // Basic CPU and speed detection routines 
    // Copyright (c) 1995, Intel Corporation.  All rights reserved.
    //////////////////////////////////////////////////////////////////////
    
    #include "stdafx.h"
    #include "CpuIdTest.h"
    #include "CpuId.h"
    
    #ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #define new DEBUG_NEW
    #endif
    
    typedef unsigned short ushort;
    typedef unsigned long  ulong;
    
    #define CPU_ID __asm _emit 0x0f __asm _emit 0xa2 	
    										// CPUID instruction
    
    #define RDTSC  _asm _emit 0x0f _asm _emit 0x31	
    										// RDTSC instruction
    
    // CONSTANT DEFINITIONS ////////////////////////////////////////
    #define CLONE_MASK		0x8000	// Mask to be 'OR'ed with proc-
    #define MAXCLOCKS		150		// Maximum number of cycles per
    								//   BSF instruction
    	// ACCURACY AFFECTING CONSTANTS ////////////////////////////
    #define ITERATIONS		4000	// Number of times to repeat BSF
    								//   instruction in samplings.
    								//   Initially set to 4000.
    
    #define MAX_TRIES		20		// Maximum number of samplings
    								//   to allow before giving up
    								//   and returning current 
    								//   average. Initially set to
    								//   20.
    
    #define TOLERANCE		1		// Number of MHz to allow
    								//   samplings to deviate from
    								//   average of samplings.
    								//   Initially set to 2.
    
    #define	SAMPLINGS		10		// Number of BSF sequence 
    								//   samplings to make.
    								//   Initially set to 10.
    
    #define ROUND_THRESHOLD		6
    
    struct FREQ_INFO
    {
    	unsigned long in_cycles;	// Internal clock cycles during
    								//   test
    
    	unsigned long ex_ticks;		// Microseconds elapsed during 
    								//   test
    
    	unsigned long raw_freq;		// Raw frequency of CPU in MHz
    
    	unsigned long norm_freq;	// Normalized frequency of CPU
    								//   in MHz.
    };
    
    // Number of cycles needed to execute a single BSF instruction.
    //    Note that processors below i386(tm) are not supported.
    static ulong processor_cycles[] = {
    	00,  00,  00, 115, 47, 43, 
    	38,  38,  38, 38,  38, 38, 
    };
    
    //////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////
    
    CCpuId::CCpuId()
    {
    
    }
    
    CCpuId::~CCpuId()
    {
    
    }
    
    /***************************************************************
    * check_clone()
    *
    * Inputs: none
    *
    * Returns:
    *   1      if processor is clone (limited detection ability)
    *   0      otherwise
    ***************************************************************/
    
    static bool check_clone()
    {
    	short cpu_type=0;
    
    	_asm 
    		{
      					MOV AX,5555h	// Check to make sure this
    					XOR DX,DX		//   is a 32-bit processor
    					MOV CX,2h
    					DIV CX			// Perform Division
    					CLC
    					JNZ no_clone
    					JMP clone
    		no_clone:	STC
    		clone:		PUSHF
    					POP AX          // Get the flags
    					AND AL,1
    					XOR AL,1        // AL=0 is probably Intel,
    									//   AL=1 is a Clone
    
    					MOV cpu_type, ax
    		}
    
        cpu_type = cpu_type & 0x0001;
    
    	if(cpu_type)
    		return TRUE;
    	else
    		return FALSE;		
    }
    
    /***************************************************************
    * check_IDProc()
    *
    * Inputs: none
    *
    * Returns:
    *  CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
    *
    ***************************************************************/
    
    static WORD check_IDProc() {
    
    		int i=0;
    		WORD cpu_type=0xffff;
    		BYTE stepping=0;
    		BYTE model=0;
    		BYTE vendor_id[]="------------";
    		BYTE intel_id[]="GenuineIntel";
    
    __asm {      
    
           xor     eax, eax
    
           CPU_ID
    
           mov     dword ptr vendor_id, ebx 
           mov     dword ptr vendor_id[+4], edx 
           mov     dword ptr vendor_id[+8], ecx 
    }
    
    __asm {
    
            cmp     eax, 1			// Make sure 1 is valid input 
            						//   for CPUID
    
            jl      end_IDProc		// If not, jump to end
            xor     eax, eax
            inc		eax
            CPU_ID					// Get family/model/stepping/
            						//   features
    
    		mov 	stepping, al
    		and		stepping, 0x0f //0fh
    
    		and 	al, 0f0h
    		shr		al, 4
    		mov 	model, al
    
    		and		eax, 0f00h
            shr     eax, 8			// Isolate family
    		and		eax, 0fh
            mov     cpu_type, ax	// Set _cpu_type with family
    
    end_IDProc:
    		mov		ax, cpu_type
          }
    
    	return cpu_type;
    
    } // Check_IDProc()
    
    int wincpuidsupport()
    {
    	int cpuid_support = 1;
    
    	_asm {
            pushfd					// Get original EFLAGS
    		pop		eax
    		mov 	ecx, eax
            xor     eax, 200000h	// Flip ID bit in EFLAGS
            push    eax				// Save new EFLAGS value on
            						//   stack
            popfd					// Replace current EFLAGS value
            pushfd					// Get new EFLAGS
            pop     eax				// Store new EFLAGS in EAX
            xor     eax, ecx		// Can not toggle ID bit,
            jnz     support			// Processor=80486
    
    		mov cpuid_support,0		// Clear support flag
    support:
          }
    
    	return cpuid_support;
    
    }
    
    /***************************************************************
    * wincpuid()
    *
    * Inputs: none
    *
    * Returns:
    *  0 = Unknown
    *  2 = 80286
    *  3 = 80386
    *  4 = 80486
    *  5 = Pentium(R) Processor
    *  6 = PentiumPro(R) Processor
    *  7 or higher = Processor beyond the PentiumPro6(R) Processor
    *
    ***************************************************************/
    
    int wincpuid() 
    {
    	int cpuid;
    	bool clone_flag = FALSE;
    
    	if ( wincpuidsupport() ) 	// Determine whether CPUID 
    								//   opcode is supported
    		cpuid=check_IDProc();
    
    	else {
    
    		clone_flag=check_clone();
    
            cpuid=0;
    	}
    
    	if (clone_flag)
    		cpuid = cpuid | CLONE_MASK;	// Signify that a clone has been
    									//   detected by setting MSB high 
    
       	return cpuid;
    }
    
    void GetCpuString(int type, CString *str)
    {
    	switch (type)
    	{
    	case 3:
    		*str = "386";
    		break;
    
    	case 4:
    		*str = "486";
    		break;
    
    	case 5:
    		*str = "Pentium(R) Processor";
    		break;
    
    	case 6:
    		*str = "PentiumPro(R) Processor";
    		break;
    
    	default:
    		str->Format("Unknown Type (%d)", type);
    		break;
    	}
    }
    
    void CCpuId::GetCpuId(CString * CpuIdStr)
    {
    	int	cpu_type;
    	int	cpuid_support;
    	CString tStr;
    
    	cpu_type = wincpuid();
    	cpuid_support = wincpuidsupport();
    
    	GetCpuString(cpu_type, &tStr);
    
    	if ( cpu_type & CLONE_MASK )
    		CpuIdStr->Format("Intel Clone CPU Family : %s", (LPCTSTR)tStr);
    	else 
    	if ( cpuid_support )				
    		CpuIdStr->Format("Intel CPU Family : %s", (LPCTSTR)tStr);
    	else
    		CpuIdStr->Format("CPU Family : %s", (LPCTSTR)tStr);
    }
    
    /***************************************************************
    * wincpufeatures()
    *
    * Inputs: none
    *
    * Returns:
    *   0 = Processor which does not execute the CPUID instruction.
    *          This includes 8086, 8088, 80286, 80386, and some 
    *		   older 80486 processors.                       
    *
    * Else
    *   Feature Flags (refer to App Note AP-485 for description).
    *      This DWORD was put into EDX by the CPUID instruction.
    *
    *	Current flag assignment is as follows:
    *
    *		bit31..10   reserved (=0)
    *		bit9=1      CPU contains a local APIC (iPentium-3V)
    *		bit8=1      CMPXCHG8B instruction supported
    *		bit7=1      machine check exception supported
    *		bit6=0      reserved (36bit-addressing & 2MB-paging)
    *		bit5=1      iPentium-style MSRs supported
    *		bit4=1      time stamp counter TSC supported
    *		bit3=1      page size extensions supported
    *		bit2=1      I/O breakpoints supported
    *		bit1=1      enhanced virtual 8086 mode supported
    *		bit0=1      CPU contains a floating-point unit (FPU)
    *
    *	Note: New bits will be assigned on future processors... see
    *         processor data books for updated information
    *
    ***************************************************************/
    
    DWORD wincpufeatures() {
    
    	int i=0;
    	DWORD cpuff=0x00000000;
    	BYTE vendor_id[]="------------";
    	BYTE intel_id[]="GenuineIntel";
    
    	if ( wincpuidsupport() ) {
    
    _asm {      
    
    		xor     eax, eax		// Set up for CPUID instruction
    
    		CPU_ID                  // Get and save vendor ID
    
            mov     dword ptr vendor_id, ebx
            mov     dword ptr vendor_id[+4], edx
            mov     dword ptr vendor_id[+8], ecx
    }
    
    _asm {
    
    		cmp     eax, 1			// Make sure 1 is valid input 
            						//   for CPUID
    
            jl      end_cpuff		// If not, jump to end
            xor     eax, eax
            inc		eax
            CPU_ID					// Get family/model/stepping/
            						//   features
    
    		mov		cpuff, edx
    
    end_cpuff:
    		mov		eax, cpuff
          }
    	}
    
    	return cpuff;
    
    }
    
    static void GetRDTSCCpuSpeed(struct FREQ_INFO *cpu_speed)
    {
    	LARGE_INTEGER t0,t1;			// Variables for High-
    									//   Resolution Performance
    									//   Counter reads
    
    	ulong freq  =0;			// Most current frequ. calculation
    	ulong freq2 =0;			// 2nd most current frequ. calc.
    	ulong freq3 =0;			// 3rd most current frequ. calc.
    
    	ulong total;			// Sum of previous three frequency
    							//   calculations
    
    	int tries=0;			// Number of times a calculation has
    							//   been made on this call to 
    							//   cpuspeed
    
    	ulong  total_cycles=0, cycles;	// Clock cycles elapsed 
    									//   during test
    
    	ulong  stamp0, stamp1;			// Time Stamp Variable 
    									//   for beginning and end 
    									//   of test
    
    	ulong  total_ticks=0, ticks;	// Microseconds elapsed 
    									//   during test
    
    	LARGE_INTEGER count_freq;		// High Resolution 
    									//   Performance Counter 
    									//   frequency
    
    #ifdef WIN32
    	int iPriority;
    	HANDLE hThread = GetCurrentThread();
    #endif // WIN32;
    
    	memset(cpu_speed, 0x00, sizeof(cpu_speed));
    
    	if ( !QueryPerformanceFrequency ( &count_freq ) )
    		return;
    
    	// On processors supporting the Read 
    	//   Time Stamp opcode, compare elapsed
    	//   time on the High-Resolution Counter
    	//   with elapsed cycles on the Time 
    	//   Stamp Register.
    
    	do {			// This do loop runs up to 20 times or
    	   				//   until the average of the previous 
    	   				//   three calculated frequencies is 
    	   				//   within 1 MHz of each of the 
    	   				//   individual calculated frequencies. 
    					//   This resampling increases the 
    					//   accuracy of the results since
    					//   outside factors could affect this
    					//   calculation
    
    		tries++;		// Increment number of times sampled
    						//   on this call to cpuspeed
    
    		freq3 = freq2;	// Shift frequencies back to make
    		freq2 = freq;	//   room for new frequency 
    						//   measurement
    
        	QueryPerformanceCounter(&t0);	
        					// Get high-resolution performance 
        					//   counter time
    
    		t1.LowPart = t0.LowPart;		// Set Initial time
    		t1.HighPart = t0.HighPart;
    
    #ifdef WIN32
    		iPriority = GetThreadPriority(hThread);
    		if ( iPriority != THREAD_PRIORITY_ERROR_RETURN )
    		{
    			SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
    		}
    #endif // WIN32
    
       		while ( (ulong)t1.LowPart - (ulong)t0.LowPart<50) {	  
       						// Loop until 50 ticks have 
       						//   passed	since last read of hi-
    						//	 res counter. This accounts for
    						//   overhead later.
    
    			QueryPerformanceCounter(&t1);
    
    			RDTSC;						// Read Time Stamp
    			_asm {
    				MOV stamp0, EAX
    			}
    		}
    
    		t0.LowPart = t1.LowPart;		// Reset Initial 
    		t0.HighPart = t1.HighPart;		//   Time
    
       		while ((ulong)t1.LowPart-(ulong)t0.LowPart<1000 ) {
       						// Loop until 1000 ticks have 
       						//   passed	since last read of hi-
       						//   res counter. This allows for
    						//   elapsed time for sampling.
    
       			QueryPerformanceCounter(&t1);
    
    			RDTSC;						// Read Time Stamp
    			__asm {
    				MOV stamp1, EAX
    			}
    		}
    
    #ifdef WIN32
    		// Reset priority
    		if ( iPriority != THREAD_PRIORITY_ERROR_RETURN )
    		{
    			SetThreadPriority(hThread, iPriority);
    		}
    #endif // WIN32
    
           	cycles = stamp1 - stamp0;	// Number of internal 
            							//   clock cycles is 
            							//   difference between 
            							//   two time stamp 
            							//   readings.
    
        	ticks = (ulong) t1.LowPart - (ulong) t0.LowPart;	
    								// Number of external ticks is
    								//   difference between two
    								//   hi-res counter reads.
    
    		// Note that some seemingly arbitrary mulitplies and
    		//   divides are done below. This is to maintain a 
    		//   high level of precision without truncating the 
    		//   most significant data. According to what value 
    		//   ITERATIIONS is set to, these multiplies and
    		//   divides might need to be shifted for optimal
    		//   precision.
    
    		ticks = ticks * 100000;	
    							// Convert ticks to hundred
    							//   thousandths of a tick
    
    		ticks = ticks / ( count_freq.LowPart/10 );		
    							// Hundred Thousandths of a 
    							//   Ticks / ( 10 ticks/second )
    							//   = microseconds (us)
    
    		total_ticks += ticks;
    		total_cycles += cycles;
    
    		if ( ticks%count_freq.LowPart > count_freq.LowPart/2 )
    			ticks++;			// Round up if necessary
    
    		freq = cycles/ticks;	// Cycles / us  = MHz
    
         	if ( cycles%ticks > ticks/2 )
           		freq++;				// Round up if necessary
    
    		total = ( freq + freq2 + freq3 );
    							// Total last three frequency 
    							//   calculations
    
    	} while ( (tries < 3 ) || 		
    	          (tries < 20)&&
    	          ((abs(3 * freq -total) > 3*TOLERANCE )||
    	           (abs(3 * freq2-total) > 3*TOLERANCE )||
    	           (abs(3 * freq3-total) > 3*TOLERANCE )));	
    					// Compare last three calculations to 
    	          		//   average of last three calculations.		
    
    	// Try one more significant digit.
    	freq3 = ( total_cycles * 10 ) / total_ticks;
    	freq2 = ( total_cycles * 100 ) / total_ticks;
    
    	if ( freq2 - (freq3 * 10) >= ROUND_THRESHOLD )
    		freq3++;
    
    	cpu_speed->raw_freq = total_cycles / total_ticks;
    	cpu_speed->norm_freq = cpu_speed->raw_freq;
    
    	freq = cpu_speed->raw_freq * 10;
    	if( (freq3 - freq) >= ROUND_THRESHOLD )
    		cpu_speed->norm_freq++;
    
    	cpu_speed->ex_ticks = total_ticks;
    	cpu_speed->in_cycles = total_cycles;
    
    	return;
    }
    
    int GetCmosTick(void)
    {
    	int tick = 0;
    
    	// __asm	mov ah, 02h
    	// __asm	int 1Ah
    	// __asm	mov al, dh
    	// __asm	and ax, 000Fh  
    
    	__asm  xor ax, ax
    	__asm  out 070h, al
    
    	__asm  xor ax, ax
    	__asm  in  al, 071h
    
        // _outp( 0x70, offset );
        // base = _inp( 0x71 ); 
    
    // value returned in ax by function
    
    	__asm 	mov word ptr tick, ax
    
    	return tick;
    }
    
    //***************************************************************
    //
    // Function: cpuTimeStamp
    //
    //		Returns the pentium cpu time stamp in 2 32 bit unsigned longs
    //
    //	Notes: maintains a flag to make sure the cpu supports the RDTSC instruction.  There is
    //		the overhead of checking the cpu the first time afterwhich the time consumed in 
    //		checking the flag is very minimal.  You could adjust the count but then you would
    //		have to do 64bit math.  ugh.
    //
    //***************************************************************
    unsigned long cpuTimeStamp(unsigned long *hi, unsigned long *low)
    {
    	unsigned long ulHi = 0L;
    	unsigned long ulLow = 0L;
    	__asm {
    		;RDTSC
    		_emit 0Fh
    		_emit 31h
    		mov ulLow, eax
    		mov ulHi, edx
    	}		
    
    	*hi = ulHi;
    	*low = ulLow;
    
    	return ulLow;		
    }	
    
    //***************************************************************
    //
    // Function: diffTime64
    //
    //		Calculates the difference of a 64 bit time as represented by
    //		two 32 bit unsigned longs
    //
    //***************************************************************
    unsigned long diffTime64(unsigned long t1Hi, unsigned long t1Low, 
    						 unsigned long t2Hi, unsigned long t2Low, 
     					 	 unsigned long *tHi, unsigned long *tLow )
    {
    	unsigned long xl, xh;
    
    /*
    	*tHi = t2Hi - t1Hi;
    
    	if( t1Low > t2Low )
    	{
    		*tLow = t1Low - t2Low;
    		*tLow = ULONG_MAX - *tLow; 		
    		*tHi -= 1;
    
    	} else {
    		*tLow = t2Low - t1Low;
    	}
    */
    
    	__asm {
    		mov eax, t2Low
    		mov ebx, t1Low
    		sub eax, ebx
    		mov xl, eax
    		mov eax, t2Hi
    		mov ebx, t1Hi
    		sbb eax, ebx
    		mov xh, eax
    	}
    
    	*tLow = xl;
    	*tHi  = xh;
    
    	return *tLow;
    
    }	
    
    #define ABS_TICK(a,b)  (b<a)?b+10-a:b-a
    
    static void GetCmosCpuSpeed(struct FREQ_INFO *cpu_speed)
    {
    	unsigned long 	t1Low, t1High, t2Low, t2High, tResLow, tResHigh;
    	int	timeStart, timeStop, lapseTime;
    	unsigned long   temp;
    	unsigned long   temp1;
    	unsigned long   cpuSpeed = 0l;
    #ifdef WIN32
    	HANDLE	hThread = GetCurrentThread();
    	int		iPriority;
    #endif // WIN32
    
    	memset(cpu_speed, 0x00, sizeof(cpu_speed));
    
    	// This loop waits for the next tick
    	// so that we begin speed test on a tick edge
    #ifdef WIN32
    		iPriority = GetThreadPriority(hThread);
    		if ( iPriority != THREAD_PRIORITY_ERROR_RETURN )
    		{
    			SetThreadPriority(hThread, iPriority+1);
    		}
    #endif // WIN32
    
    	timeStart = GetCmosTick();
    	for(;;)
    	{
    		timeStop = GetCmosTick();
    		if (  ABS_TICK(timeStart,timeStop) > 0 )
    		{
    			cpuTimeStamp(&t1High, &t1Low);
    			break;	
    		}	
    	}
    
    	timeStart = timeStop;
    
    	for(;;)
    	{
    		timeStop = GetCmosTick();
    		if (  ABS_TICK(timeStart,timeStop) > 0 )
    		{
    			cpuTimeStamp(&t2High, &t2Low);
    			break;	
    		}	
    	}
    
    #ifdef WIN32
    		// Set thread priority back.
    		if ( iPriority != THREAD_PRIORITY_ERROR_RETURN )
    		{
    			SetThreadPriority(hThread, iPriority);
    		}
    #endif // WIN32
    
    	diffTime64(t1High, t1Low, t2High, t2Low, &tResHigh, &tResLow );
    	lapseTime = ABS_TICK(timeStart,timeStop);
    
    	cpuSpeed = tResLow; ///lapseTime; 
    	cpu_speed->in_cycles = tResLow;		// Cycles count since we in this routine
    
    	//round to nearest digit
    	temp =  cpuSpeed/1000000; 	
    	temp1 = cpuSpeed/100000;  
    	temp = temp * 10;  // realign with last digit = zero
    
    	cpuSpeed = cpuSpeed/1000000; // cpuSpeed/1000000;
    	cpu_speed->raw_freq = cpuSpeed;	
    
    	if( (temp1 - temp) >= ROUND_THRESHOLD )
    		cpuSpeed++;
    
    	cpu_speed->norm_freq = cpuSpeed;	
    	cpu_speed->ex_ticks = (timeStop - timeStart) * 1000000;
    
    	return;			
    }
    
    static void GetBSFCpuSpeed(ulong cycles, struct FREQ_INFO *cpu_speed)
    {
    	// If processor does not support time 
    	//   stamp reading, but is at least a 
    	//   386 or above, utilize method of 
    	//   timing a loop of BSF instructions 
    	//   which take a known number of cycles
    	//   to run on i386(tm), i486(tm), and
    	//   Pentium(R) processors.
    	LARGE_INTEGER t0,t1;			// Variables for High-
    									//   Resolution Performance
    									//   Counter reads
    
    	ulong freq  =0;			// Most current frequ. calculation
    
    	ulong  ticks;					// Microseconds elapsed 
    									//   during test
    
    	LARGE_INTEGER count_freq;		// High Resolution 
    									//   Performance Counter 
    									//   frequency
    
    	int i;						// Temporary Variable
    
    	ulong current = 0;          // Variable to store time
    									//   elapsed during loop of
    									//   of BSF instructions
    
    	ulong lowest  = ULONG_MAX;	// Since algorithm finds 
    									//   the lowest value out of
    									//   a set of samplings, 
    									//   this variable is set 
    									//   intially to the max 
    									//   unsigned long value). 
    									//   This guarantees that 
    									//   the initialized value 
    									//   is not later used as 
    									//   the least time through 
    									//   the loop.
    
    	memset(cpu_speed, 0x00, sizeof(cpu_speed));
    
    	if ( !QueryPerformanceFrequency ( &count_freq ) )
    		return;
    
    	for ( i = 0; i < SAMPLINGS; i++ ) { // Sample Ten times. Can
    									 //   be increased or 
    									 //   decreased depending
    									 //   on accuracy vs. time
    									 //   requirements
    
    		QueryPerformanceCounter(&t0);	// Get start time
    
    			_asm 
    			{
    
    					mov eax, 80000000h	
    					mov bx, ITERATIONS		
    								// Number of consecutive BSF 
    								//   instructions to execute. 
    								//   Set identical to 
    								//   nIterations constant in
    								//   speed.h
    
    				loop1:	bsf ecx,eax
    
    	       				dec	bx
    						jnz	loop1
    			}
    
    		QueryPerformanceCounter(&t1);	// Get end time
    		current = (ulong) t1.LowPart - (ulong) t0.LowPart;	
    								// Number of external ticks is
    								//   difference between two
    								//   hi-res counter reads.
    
    		if ( current < lowest )		// Take lowest elapsed
    			lowest = current;		//   time to account
    	}								//   for some samplings
    										//   being interrupted
    										//   by other operations 
    
    	ticks = lowest;
    
    	// Note that some seemingly arbitrary mulitplies and
    	//   divides are done below. This is to maintain a 
    	//   high level of precision without truncating the 
    	//   most significant data. According to what value 
    	//   ITERATIIONS is set to, these multiplies and
    	//   divides might need to be shifted for optimal
    	//   precision.
    
    	ticks = ticks * 100000;	
    						// Convert ticks to hundred
    						//   thousandths of a tick
    
    	ticks = ticks / ( count_freq.LowPart/10 );		
    						// Hundred Thousandths of a 
    						//   Ticks / ( 10 ticks/second )
    						//   = microseconds (us)
    
    	if ( ticks%count_freq.LowPart > count_freq.LowPart/2 )	
    		ticks++;				// Round up if necessary
    
    	freq = cycles/ticks;		// Cycles / us  = MHz
    
    	cpu_speed->raw_freq  = freq;
        if ( cycles%ticks > ticks/2 )
       		freq++;					// Round up if necessary	
    
    	cpu_speed->in_cycles = cycles;	// Return variable structure
    	cpu_speed->ex_ticks  = ticks;	//   determined by one of 
    	cpu_speed->norm_freq = freq;
    
    	return;
    }	
    
    /***************************************************************
    * CpuSpeed() -- Return the raw clock rate of the host CPU.
    *
    * Inputs:
    *	clocks:		0: Use default value for number of cycles
    *				   per BSF instruction.
    *               -1: Use CMos timer to get cpu speed.
    *   			Positive Integer: Use clocks value for number
    *				   of cycles per BSF instruction.
    *
    * Returns:
    *		If error then return all zeroes in FREQ_INFO structure
    *		Else return FREQ_INFO structure containing calculated 
    *       clock frequency, normalized clock frequency, number of 
    *       clock cycles during test sampling, and the number of 
    *       microseconds elapsed during the sampling.
    ***************************************************************/
    
    struct FREQ_INFO wincpuspeed(int clocks) 
    {
    	ulong  cycles;					// Clock cycles elapsed 
    									//   during test
    
    	ushort processor = wincpuid();	// Family of processor
    
    	DWORD features = wincpufeatures();	// Features of Processor
    
    	int manual=0;			// Specifies whether the user 
    							//   manually entered the number of
    							//   cycles for the BSF instruction.
    
    	struct FREQ_INFO cpu_speed;		// Return structure for
    									//   cpuspeed
    
    	memset(&cpu_speed, 0x00, sizeof(cpu_speed));
    
    	if ( processor & CLONE_MASK )
    		return cpu_speed;
    
    	// Check for manual BSF instruction clock count
    	if (clocks <= 0) {
    		cycles = ITERATIONS * processor_cycles[processor];
    	}
    	else if (0 < clocks && clocks <= MAXCLOCKS)  {
    		cycles = ITERATIONS * clocks;
    		manual = 1;			// Toggle manual control flag.
    							//   Note that this mode will not
    							// 	 work properly with processors
    							//   which can process multiple
    							//   BSF instructions at a time.
    							//   For example, manual mode
    							//   will not work on a 
    							//   PentiumPro(R)
    	}
    
    	if ( ( features&0x00000010 ) && !(manual) ) {						
    						// On processors supporting the Read 
    						//   Time Stamp opcode, compare elapsed
    						//   time on the High-Resolution Counter
    						//   with elapsed cycles on the Time 
    						//   Stamp Register.
    		if ( clocks == 0 )
    			GetRDTSCCpuSpeed(&cpu_speed);
    		else
    			GetCmosCpuSpeed(&cpu_speed);
        }
    	else if ( processor >= 3 ) {
    		GetBSFCpuSpeed(cycles, &cpu_speed);
    	}
    
    	return cpu_speed;
    }
    
    void CCpuId::GetCpuSpeed(CString * CpuSpeed)
    {
    	struct FREQ_INFO cpu_speed;
    
    	cpu_speed = wincpuspeed(0);
    
    	CpuSpeed->Format("%luMHz", cpu_speed.norm_freq);
    }
    

    Beispiel:

    //Test.cpp
    #include "stdafx.h"
    #include "cpuid.h"
    #include <iostream>
    using namespace std;
    
    int main(int argc, char **argv()
    {
      CString m_cpuId, m_cpuSpeed; //Anstelle von CString geht auch string der STL
      CCpuId::GetCpuId(&m_cpuId);  //oder einfach nur ein char[] Buffer
      CCpuId::GetCpuSpeed(&m_cpuSpeed);
      cout << "CPU-Speed: " << m_cpuSpeed << endl;
      cout << "CPU-Type: " << m_cpuId << endl;
    }
    

    Gruss René

    PS: Hoffentlich werde ich jetzt nicht gesteinigt... 😮


Anmelden zum Antworten