[x]
Posted via EE Mobile

Search, ask, and monitor your questions on the go with EE Mobile. Visit Experts Exchange from your mobile device and never be out of touch again.

Question
[x]
Attachment Details
[x]
The Solution Rating System

With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.

  • The Grade of the Solution
  • The Zone Rank of the Expert Providing the Solution
  • The Number of Author and Expert Comments
  • The Number of Experts Contributing
  • The Feedback of the Community

Your Input Matters
Because of the way the system is set up, the most important variable in this equation is you. As a member of Experts Exchange, you are able to cast your vote on the quality of the solutions in regard to how complete, accurate, helpful and easy to understand each solution is. When you provide your feedback, each rating is adjusted accordingly. So, if you see a solution that has a poor rating that you think is a good solution, let us know by rating it. As you do, the rating will be adjusted and will become more accurate for other members of our site.

If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support.

Thank you!

9.2

SysInfo App will not run in release mode

Asked by Bkey1 in C++ Programming Language

For the past several days I have been working on rewriting several functions that get the CPU type and speed of the current system to use Win32API functions instead of being dependent upon MFC.  I did this so that I could add CPU detection capabilities to an existing Win32API application I have been developing for the past several months.  Tonight I was able to finally complete this task and to compile and run the program in debug mode.  However, when I run the program after compiling it in release mode I get the following error:
Unhandled Exception in SysInfo.exe: 0xC0000005: Access Violation.

Then of course the program exits and I am taken to a program disassembly screen.  Even though I do not understand the content of the program disassembly screen, I have been able to trace the cause of the problem to one of the assembly language statements in the file CpuId.cpp, the text of which I will include below.

As far as these particular lines of these functions go, I am way over my head.  I do not understand any of them so I am totally unable to resolve the problem.  All I know is that these same lines were taken from the MFC project they were origionally a part of and were not changed with the exception of some formatting improvements.  I also know that the project they were origionally taken from works equally well in release and debug mode.   So I am at a total loss on how to fix the problem at hand.

Well, enough chatter for now.  Here is the text of the file that I feel is the cause of my problems.  I would appreciate any ideas you may have.

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include "SysInfo.h"

// Define the CPUID instruction
#define CPU_ID __asm _emit 0x0f __asm _emit 0xa2       
// Define the RDTSC instruction
#define RDTSC  _asm _emit 0x0f _asm _emit 0x31      

// 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
// Number of times to repeat BSF instruction in samplings.  Initially set to 4000.
#define ITERATIONS                        4000
// Maximum number of samplings to allow before giving up and returning current
// average. Initially set to 20.
#define MAX_TRIES                              20
// Number of MHz to allow samplings to deviate from average of samplings.
//   Initially set to 2.
#define TOLERANCE                              2
// Number of BSF sequence samplings to make.
//   Initially set to 10.
#define      SAMPLINGS                              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,
};

/*
******************************************************************************************
Function:
      bool CSysInfo::check_clone()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Detects if the processor of the curent system is a clone.
Parameters
Globals
      Used:
      Modified:
External Functions:
Return Value:
      1            if processor is clone (limited detection ability)
      0            otherwise
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
bool CSysInfo::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;            
}

/*
******************************************************************************************
Function:
      WORD CSysInfo::check_IDProc()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Detects the system processor family.  A support function for wincpuid().
Parameters
Globals
      Used:
      Modified:
External Functions:
Return Value:
      CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
WORD CSysInfo::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()

/*
******************************************************************************************
Function:
      int CSysInfo::wincpuidsupport()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Detects the system processor family.  A support function for wincpuid().
Parameters
Globals
      Used:
      Modified:
External Functions:
Return Value:
      CPU Family (i.e. 4 if Intel 486, 5 if Pentium(R) Processor)
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
int CSysInfo::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;
}

/*
******************************************************************************************
Function:
      int CSysInfo::wincpuid()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Detects the system processor family.  Uses the functions check_clone(), check_IDProc(),
      and wincpuidsupport() to obtain the required information.
Parameters
Globals
      Used:
      Modified:
External Functions:
Return Value:
      An integer value representing the CPU family.
      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
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
int CSysInfo::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;
}

/*
******************************************************************************************
Function:
      LPCTSTR CSysInfo::GetCpuString(int type)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      This function is used to convert a numeric identifier of the CPU family to a string
      description of the CPU Type.
Parameters:
      int type      The numeric CPU type identifier.
Globals
      Used:
      Modified:
External Functions:
Return Value:
      LPCTSTR            A long pointer to a string that provides a description of the CPU type.
            I.E.  386, 486, Pentium(R) Processor, PentiumPro(R) Processor
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
LPCTSTR CSysInfo::GetCpuString(int type)
{
      LPTSTR szCPUType;
      switch (type)
      {
            case 3:
                  szCPUType = new char [5];
                  strcpy (szCPUType, "386");
                  break;
            case 4:
                  szCPUType = new char [5];
                  strcpy (szCPUType, "486");
                  break;
            case 5:
                  szCPUType = new char [strlen ("Pentium(R) Processor") + 2];
                  strcpy (szCPUType, "Pentium(R) Processor");
                  break;
            case 6:
                  szCPUType = new char [strlen ("PentiumPro(R) Processor") + 2];
                  strcpy (szCPUType, "PentiumPro(R) Processor");
                  break;
            default:
                  szCPUType = new char [strlen ("Unknown Type: (7)") + 5];
                  sprintf (szCPUType, "Unknown Type: (%d)", type);
                  break;
      }
      return (LPCTSTR) szCPUType;
}

/*
******************************************************************************************
Function:
      LPCTSTR CSysInfo::GetCpuId()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      This function is used to obtain a full description of the current CPU type, including
      the processor class and whether or not it is a Genuine Intel processor or an Intel Clone
      processor.
Parameters:
Globals
      Used:
      Modified:
External Functions:
Return Value:
      LPCTSTR            A long pointer to a string that provides the complete description of the CPU type.
                                    I.E.  Intel CPU Family : Pentium(R) Processor
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
LPCTSTR CSysInfo::GetCpuId()
{
      int      cpu_type;
      int      cpuid_support;
      LPTSTR szStr;
      LPTSTR szCpuIdStr;
      szStr = new char [50];
      szCpuIdStr = new char [100];
      cpu_type = this->wincpuid();
      cpuid_support = this->wincpuidsupport();
      strcpy (szStr, this->GetCpuString(cpu_type));
      if (cpu_type & CLONE_MASK)
            sprintf (szCpuIdStr, "Intel Clone CPU Family: %s", (LPCTSTR)szStr);
      else
      {
            if (cpuid_support)
                  sprintf (szCpuIdStr, "Intel CPU Family: %s", (LPCTSTR)szStr);
            else
                  sprintf (szCpuIdStr, "CPU Family: %s", (LPCTSTR)szStr);
      }
      return (LPCTSTR) szCpuIdStr;
}

/*
******************************************************************************************
Function:
      DWORD CSysInfo::wincpufeatures()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      This function is used to obtain the CPU feature flags that are supported by the system.
Parameters:
Globals
      Used:
      Modified:
External Functions:
Return Value:
      DWORD            The supported Feature Flags
      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
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
DWORD CSysInfo::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;
}

/*
******************************************************************************************
Function:
      void CSysInfo::GetRDTSCCpuSpeed(struct FREQ_INFO *cpu_speed)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      A supporting function for CSysInfo that is used to get the CPU speed.  It is used to
      fill the members of the FREQ_INFO structure defined above.
Parameters:
      struct FREQ_INFO *cpu_speed
            This parameter is the cpu_speed structure that is passed to the function by reference
            so that the function may fill the values stored by the structure.
Globals
      Used:
      Modified:
External Functions:
Return Value:
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
void CSysInfo::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;
}

/*
******************************************************************************************
Function:
      int CSysInfo::GetCmosTick()
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      A supporting function for CSysInfo that is used to get the tick count from CMOS.
Parameters:
Globals
      Used:
      Modified:
External Functions:
Return Value:
      Int            The tick count as obtained from CMOS.
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
int CSysInfo::GetCmosTick()
{
      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:
      unsigned long CSysInfo::cpuTimeStamp(unsigned long *hi, unsigned long *low)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      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.
Parameters:
      unsigned long *hi
      unsigned long *low
Globals
      Used:
      Modified:
External Functions:
Return Value:
      Int            The tick count as obtained from CMOS.
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
unsigned long CSysInfo::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:
      unsigned long CSysInfo::diffTime64(unsigned long t1Hi, unsigned long t1Low,
            unsigned long t2Hi, unsigned long t2Low, unsigned long *tHi, unsigned long *tLow)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Calculates the difference of a 64 bit time as represented by two 32 bit unsigned longs.
Parameters:
      unsigned long t1Hi
      unsigned long t1Low
      unsigned long t2Hi
      unsigned long t2Low
      unsigned long *tHi
      unsigned long *tLow
Globals
      Used:
      Modified:
External Functions:
Return Value:
      Int            The tick count as obtained from CMOS.
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
unsigned long CSysInfo::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

/*
******************************************************************************************
Function:
      void CSysInfo::GetCmosCpuSpeed(struct FREQ_INFO *cpu_speed)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Gets the CPU Speed from CMOS
Parameters:
      struct FREQ_INFO *cpu_speed     A FREQ_INFO structure that is passed to the function by
                                                                                                      reference.
Globals
      Used:
      Modified:
External Functions:
Return Value:
      Int            The tick count as obtained from CMOS.
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
void CSysInfo::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;                  
}

/*
******************************************************************************************
Function:
      void CSysInfo::GetBSFCpuSpeed(ulong cycles, struct FREQ_INFO *cpu_speed)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Gets the CPU Speed from CMOS
Parameters:
      struct FREQ_INFO *cpu_speed     A FREQ_INFO structure that is passed to the function by
                                                                                                      reference.
Globals
      Used:
      Modified:
External Functions:
Return Value:
      Int            The tick count as obtained from CMOS.
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
void CSysInfo::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.
      ulong freq;
      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;
}      

/*
******************************************************************************************
Function:
      struct FREQ_INFO CSysInfo::wincpuspeed(int clocks)
Author's Name:
      Ben Key
Creation Date:
      08/17/1999
Description:
      Return the raw clock rate of the host CPU.
Parameters:
      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.      
Globals
      Used:
      Modified:
External Functions:
Return Value:
      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.
Other Information:
******************************************************************************************
                                            MODIFICATION LOG
Date                                                Author                                    Description
---------------                  -----------                        ------------------------------------------
08/17/1999                              Ben Key                                    CPU Identification functions added to project.
******************************************************************************************
*/
struct FREQ_INFO CSysInfo::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;
}


LPCTSTR CSysInfo::GetCpuSpeed()
{
      LPTSTR szTemp;
      LPTSTR szCPUSpeed;
      szTemp = new char [20];
      szCPUSpeed = new char [20];
      struct FREQ_INFO cpu_speed;
      cpu_speed = wincpuspeed(0);
      sprintf (szCPUSpeed, "%i %s", cpu_speed.norm_freq, "MHz");
      return (LPCTSTR) szCPUSpeed;
}

[+][-]08/21/99 10:24 PM, ID: 1202971Expert Comment

At Experts Exchange, members can ask their questions to thousands of technology professionals, also known as Experts. Experts compete and collaborate to answer those questions by leaving comments like this one.

Start your 30-day free trial to view this Expert Comment or ask the Experts your question.

 
[+][-]08/21/99 11:00 PM, ID: 1202972Expert Comment

At Experts Exchange, members can ask their questions to thousands of technology professionals, also known as Experts. Experts compete and collaborate to answer those questions by leaving comments like this one.

Start your 30-day free trial to view this Expert Comment or ask the Experts your question.

 
[+][-]08/22/99 12:36 PM, ID: 1202973Author Comment

Often, when Experts are collaborating with members who have asked questions, they will request additional information about the problem. Askers respond with an author comment like this one.

Start your 30-day free trial to view this Author Comment or ask the Experts your question.

 
[+][-]08/23/99 06:30 AM, ID: 1202974Expert Comment

At Experts Exchange, members can ask their questions to thousands of technology professionals, also known as Experts. Experts compete and collaborate to answer those questions by leaving comments like this one.

Start your 30-day free trial to view this Expert Comment or ask the Experts your question.

 
[+][-]08/24/99 04:13 AM, ID: 1202975Expert Comment

At Experts Exchange, members can ask their questions to thousands of technology professionals, also known as Experts. Experts compete and collaborate to answer those questions by leaving comments like this one.

Start your 30-day free trial to view this Expert Comment or ask the Experts your question.

 
[+][-]08/25/99 02:30 PM, ID: 1202976Author Comment

Often, when Experts are collaborating with members who have asked questions, they will request additional information about the problem. Askers respond with an author comment like this one.

Start your 30-day free trial to view this Author Comment or ask the Experts your question.

 
[+][-]08/25/99 02:42 PM, ID: 1202977Accepted Solution

View this solution now by starting your 30-day free trial. Setting up your free trial is quick, easy, and secure. We will return you to this solution, unlocked, when you're done.

About this solution

Zone: C++ Programming Language
Sign Up Now!
Solution Provided By: chensu
Participating Experts: 4
Solution Grade: A
 
 
Loading Advertisement...
20091021-EE-VQP-81