home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2005 March / PCpro_2005_03.ISO / files / systools / speedswitchxp / sswitchxp14.exe / Typical / Speed.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-01-14  |  12.9 KB  |  353 lines

  1. /***************************************************************
  2. * C file:  Speed.c... for cpuinf32 DLL
  3. *
  4. *       This program has been developed by Intel Corporation.  
  5. *       You have Intel's permission to incorporate this code 
  6. *       into your product, royalty free.  Intel has various 
  7. *       intellectual property rights which it may assert under
  8. *       certain circumstances, such as if another manufacturer's
  9. *       processor mis-identifies itself as being "GenuineIntel"
  10. *       when the CPUID instruction is executed.
  11. *
  12. *       Intel specifically disclaims all warranties, express or
  13. *       implied, and all liability, including consequential and
  14. *       other indirect damages, for the use of this code, 
  15. *       including liability for infringement of any proprietary
  16. *       rights, and including the warranties of merchantability
  17. *       and fitness for a particular purpose.  Intel does not 
  18. *       assume any responsibility for any errors which may 
  19. *       appear in this code nor any responsibility to update it.
  20. *
  21. *  * Other brands and names are the property of their respective
  22. *    owners.
  23. *
  24. *  Copyright (c) 1995, Intel Corporation.  All rights reserved.
  25. *
  26. *  Runtime optimizations & modifications by Christian Diefer
  27. ***************************************************************/
  28.  
  29. #include "stdafx.h"
  30. #include <stdio.h>
  31. #include <math.h>
  32. #include <limits.h>
  33.  
  34. #include "speed.h"
  35. #include "cpuid.h"
  36.  
  37. #define ROUND_THRESHOLD 6
  38.  
  39. static struct FREQ_INFO GetRDTSCCpuSpeed();
  40. static struct FREQ_INFO GetBSFCpuSpeed(ulong cycles);
  41.  
  42. // Number of cycles needed to execute a single BSF instruction.
  43. //    Note that processors below i386(tm) are not supported.
  44. static ulong processor_cycles[] = {
  45.     00,  00,  00, 115, 47, 43, 
  46.     38,  38,  38, 38,  38, 38, 
  47. };
  48.  
  49. ushort sproc;
  50. DWORD sfeat;
  51. static int firstrun = 1;
  52.  
  53. /***************************************************************
  54. * CpuSpeed() -- Return the raw clock rate of the host CPU.
  55. *
  56. * Inputs:
  57. *   clocks:     0: Use default value for number of cycles
  58. *                  per BSF instruction.
  59. *               -1: Use CMos timer to get cpu speed.
  60. *               Positive Integer: Use clocks value for number
  61. *                  of cycles per BSF instruction.
  62. *
  63. * Returns:
  64. *       If error then return all zeroes in FREQ_INFO structure
  65. *       Else return FREQ_INFO structure containing calculated 
  66. *       clock frequency, normalized clock frequency, number of 
  67. *       clock cycles during test sampling, and the number of 
  68. *       microseconds elapsed during the sampling.
  69. ***************************************************************/
  70.  
  71. struct FREQ_INFO cpuspeed( int clocks ) 
  72. {
  73.   ulong cycles=0;              // Clock cycles elapsed during test
  74.   struct FREQ_INFO cpu_speed;  // Return structure for cpuspeed
  75.   ushort processor;            // Family of processor
  76.   DWORD features;              // Features of Processor
  77.  
  78.  
  79.   if( firstrun )
  80.   {
  81.     processor = sproc = wincpuid();
  82.     features = sfeat = wincpufeatures();
  83.     firstrun = 0;
  84.   }
  85.   else
  86.   {
  87.     processor = sproc;
  88.     features = sfeat;
  89.   }
  90.  
  91.   memset( &cpu_speed, 0x00, sizeof(cpu_speed) );
  92.  
  93.   // Check for manual BSF instruction clock count
  94.   cycles = ITERATIONS * processor_cycles[processor];
  95.  
  96.   if( features & TSC_SUPPORT )
  97.   {                       
  98.     // On processors supporting the Read Time Stamp opcode, compare elapsed time on
  99.     //   the High-Resolution Counter with elapsed cycles on the Time Stamp Register.
  100.     return GetRDTSCCpuSpeed();
  101.   }
  102.   else if( processor >= 3 ) 
  103.     return GetBSFCpuSpeed( cycles );
  104.  
  105.   return cpu_speed;
  106. } // cpuspeed()
  107.  
  108.  
  109. static struct FREQ_INFO GetBSFCpuSpeed( ulong cycles )
  110. {
  111.   // If processor does not support time stamp reading, but is at least a 386 or above, utilize method of 
  112.   //   timing a loop of BSF instructions which take a known number of cycles to run on i386(tm), i486(tm), 
  113.   //   and Pentium(R) processors.
  114.  
  115.   LARGE_INTEGER t0,t1;        // Variables for High-Resolution Performance Counter reads
  116.   ulong freq = 0;             // Most current frequ. calculation
  117.   ulong ticks;                // Microseconds elapsed during test
  118.   LARGE_INTEGER count_freq;   // High Resolution Performance Counter frequency
  119.   int i;                      // Temporary Variable
  120.   ulong current = 0;          // Variable to store time elapsed during loop of BSF instructions
  121.   ulong lowest = ULONG_MAX;   // Since algorithm finds the lowest value out of a set of samplings, 
  122.                               //   this variable is set intially to the max unsigned long value). 
  123.                               //   This guarantees that the initialized value is not later used as 
  124.                               //   the least time through the loop.
  125.   struct FREQ_INFO cpu_speed;
  126.  
  127.  
  128.   memset( &cpu_speed, 0x00, sizeof(cpu_speed) );
  129.  
  130.   if( !QueryPerformanceFrequency(&count_freq) )
  131.     return cpu_speed;
  132.  
  133.   for( i=0; i < SAMPLINGS; i++ )
  134.   {       
  135.     // Sample Ten times. Can be increased or decreased depending on accuracy vs. time requirements
  136.  
  137.     QueryPerformanceCounter( &t0 );   // Get start time
  138.  
  139.     _asm {
  140.         mov eax, 80000000h  
  141.         mov bx, ITERATIONS      // Number of consecutive BSF instructions to execute. Set identical to 
  142.                                 //   nIterations constant in speed.h
  143.       loop1:  
  144.         bsf ecx,eax
  145.         dec bx
  146.         jnz loop1
  147.     }
  148.                              
  149.     QueryPerformanceCounter( &t1 );   // Get end time
  150.     
  151.     // Number of external ticks is difference between two hi-res counter reads
  152.     current = (ulong) t1.LowPart - (ulong) t0.LowPart;  
  153.  
  154.     if( current < lowest )        // Take lowest elapsed time to account for some
  155.       lowest = current;           //   samplings being interrupted by other operations 
  156.   }                              
  157.          
  158.   ticks = lowest;
  159.  
  160.   // Note that some seemingly arbitrary mulitplies and divides are done below. This is to maintain a 
  161.   //   high level of precision without truncating the most significant data. According to what value 
  162.   //   ITERATIIONS is set to, these multiplies and divides might need to be shifted for optimal precision.
  163.  
  164.   ticks = ticks * 100000;         // Convert ticks to hundred thousandths of a tick
  165.             
  166.   ticks = ticks / (count_freq.LowPart/10);  // Hundred Thousandths of a Ticks / ( 10 ticks/second )
  167.                                             //   = microseconds (us)
  168.  
  169.   if( ticks%count_freq.LowPart > count_freq.LowPart/2 )  
  170.     ticks++;                      // Round up if necessary
  171.             
  172.   freq = cycles/ticks;            // Cycles / us  = MHz
  173.  
  174.   cpu_speed.raw_freq  = freq;
  175.   if( cycles%ticks > ticks/2 )
  176.     freq++;                       // Round up if necessary    
  177.  
  178.   cpu_speed.in_cycles = cycles;   // Return variable structure
  179.   cpu_speed.ex_ticks  = ticks;    //   determined by one of 
  180.   cpu_speed.norm_freq = freq;
  181.  
  182.   return cpu_speed;
  183. }   
  184.  
  185. static struct FREQ_INFO GetRDTSCCpuSpeed()
  186. {
  187.   ulong stamp0=0, stamp1=0;         // Time Stamp Variable for beginning and end of test
  188.   struct FREQ_INFO cpu_speed;
  189.   LARGE_INTEGER t0,t1;              // Variables for High-Resolution Performance Counter reads
  190.   ulong freq  =0;                   // Most current frequ. calculation
  191.   ulong freq2 =0;                   // 2nd most current frequ. calc.
  192.   ulong freq3 =0;                   // 3rd most current frequ. calc.
  193.   ulong total;                      // Sum of previous three frequency calculations
  194.   int tries=0;                      // Number of times a calculation has been made on this call to cpuspeed
  195.   ulong total_cycles=0, cycles=0;   // Clock cycles elapsed during test
  196.   ulong total_ticks=0, ticks;       // Microseconds elapsed during test
  197.   LARGE_INTEGER count_freq;         // High Resolution Performance Counter frequency
  198.  
  199. #ifdef WIN32
  200.   int iPriority;
  201.   HANDLE hThread = GetCurrentThread();
  202. #endif
  203.  
  204.  
  205.   memset( &cpu_speed, 0x00, sizeof(cpu_speed) );
  206.  
  207.   if( !QueryPerformanceFrequency(&count_freq) )
  208.     return cpu_speed;
  209.  
  210.   // On processors supporting the Read Time Stamp opcode, compare elapsed time on the 
  211.   //   High-Resolution Counter with elapsed cycles on the Time Stamp Register.
  212.     
  213.   // This do loop runs up to 20 times or until the average of the previous three calculated frequencies is 
  214.   //   within 1 MHz of each of the individual calculated frequencies. This resampling increases the 
  215.   //   accuracy of the results since outside factors could affect this calculation
  216.   do 
  217.   {          
  218.     tries++;        // Increment number of times sampled on this call to cpuspeed
  219.             
  220.     freq3 = freq2;  // Shift frequencies back to make room for new frequency measurement
  221.     freq2 = freq;
  222.  
  223.     QueryPerformanceCounter( &t0 );   // Get high-resolution performance counter time
  224.             
  225.     t1.LowPart = t0.LowPart;          // Set Initial time
  226.     t1.HighPart = t0.HighPart;
  227.  
  228. #ifdef WIN32
  229.     iPriority = GetThreadPriority( hThread );
  230.     if( iPriority != THREAD_PRIORITY_ERROR_RETURN )
  231.       SetThreadPriority( hThread, THREAD_PRIORITY_TIME_CRITICAL );
  232. #endif // WIN32
  233.  
  234.     while( (ulong)t1.LowPart-(ulong)t0.LowPart < 50 ) 
  235.     {     
  236.       // Loop until 50 ticks have passed since last read of hi-res counter. 
  237.       //   This accounts for overhead later.
  238.       QueryPerformanceCounter( &t1 );
  239.  
  240.       RDTSC;                      // Read Time Stamp
  241.       _asm {
  242.           MOV stamp0, EAX
  243.       }
  244.     }   
  245.             
  246.     t0.LowPart = t1.LowPart;        // Reset Initial Time
  247.     t0.HighPart = t1.HighPart;
  248.  
  249.     while( (ulong)t1.LowPart-(ulong)t0.LowPart < 1000 ) 
  250.     {
  251.       // Loop until 1000 ticks have passed since last read of hi-res counter. 
  252.       //   This allows for elapsed time for sampling.
  253.       QueryPerformanceCounter(&t1);
  254.   
  255.       RDTSC;                      // Read Time Stamp
  256.       __asm {
  257.            MOV stamp1, EAX
  258.       }
  259.     }
  260.  
  261. #ifdef WIN32
  262.     // Reset priority
  263.     if( iPriority != THREAD_PRIORITY_ERROR_RETURN )
  264.       SetThreadPriority( hThread, iPriority );
  265.  #endif
  266.  
  267.     // Number of internal clock cycles is difference between two time stamp readings.
  268.     cycles = stamp1 - stamp0;   
  269.  
  270.     // Number of external ticks is difference between two hi-res counter reads.
  271.     ticks = (ulong) t1.LowPart - (ulong) t0.LowPart;    
  272.  
  273.  
  274.     // Note that some seemingly arbitrary mulitplies and divides are done below. This is to maintain a 
  275.     //   high level of precision without truncating the most significant data. According to what value 
  276.     //   ITERATIIONS is set to, these multiplies and divides might need to be shifted for optimal precision.
  277.  
  278.     // Convert ticks to hundred thousandths of a tick
  279.     ticks = ticks * 100000;
  280.  
  281.     // Hundred Thousandths of a Ticks / ( 10 ticks/second ) = microseconds (us)
  282.     ticks = ticks / ( count_freq.LowPart/10 );      
  283.  
  284.     total_ticks += ticks;
  285.     total_cycles += cycles;
  286.  
  287.     if( ticks%count_freq.LowPart > count_freq.LowPart/2 )
  288.       ticks++;            // Round up if necessary
  289.  
  290.     freq = cycles/ticks;    // Cycles / us  = MHz
  291.  
  292.     if( cycles%ticks > ticks/2 )
  293.       freq++;             // Round up if necessary
  294.  
  295.     total = ( freq + freq2 + freq3 );     // Total last three frequency calculations
  296.   } while( (tries < 3 ) ||        
  297.            (tries < 20)&&
  298.            ((abs(3 * (long)freq -(long)total) > 3*TOLERANCE )||
  299.             (abs(3 * (long)freq2-(long)total) > 3*TOLERANCE )||
  300.             (abs(3 * (long)freq3-(long)total) > 3*TOLERANCE )));
  301.     // ... Compare last three calculations to average of last three calculations.                           
  302.  
  303.   // Try one more significant digit.
  304.   freq3 = ( total_cycles * 10 ) / total_ticks;
  305.   freq2 = ( total_cycles * 100 ) / total_ticks;
  306.  
  307.   if( freq2 - (freq3 * 10) >= ROUND_THRESHOLD )
  308.     freq3++;
  309.  
  310.   cpu_speed.raw_freq = total_cycles / total_ticks;
  311.   cpu_speed.norm_freq = cpu_speed.raw_freq;
  312.  
  313.   freq = cpu_speed.raw_freq * 10;
  314.   if( (freq3 - freq) >= ROUND_THRESHOLD )
  315.     cpu_speed.norm_freq++;
  316.  
  317.   cpu_speed.ex_ticks = total_ticks;
  318.   cpu_speed.in_cycles = total_cycles;
  319.  
  320.   return cpu_speed;
  321. }
  322.  
  323. //***************************************************************
  324. //
  325. // Function: cpuTimeStamp
  326. //
  327. //      Returns the pentium cpu time stamp in 2 32 bit unsigned longs
  328. //
  329. //  Notes: maintains a flag to make sure the cpu supports the RDTSC instruction.  There is
  330. //      the overhead of checking the cpu the first time afterwhich the time consumed in 
  331. //      checking the flag is very minimal.  You could adjust the count but then you would
  332. //      have to do 64bit math.  ugh.
  333. //
  334. //***************************************************************
  335. unsigned long cpuTimeStamp(unsigned long *hi, unsigned long *low)
  336. {
  337.   unsigned long ulHi = 0L;
  338.   unsigned long ulLow = 0L;
  339.  
  340.   __asm {
  341.     ;RDTSC
  342.     _emit 0Fh
  343.     _emit 31h
  344.     mov ulLow, eax
  345.     mov ulHi, edx
  346.   }       
  347.  
  348.   *hi = ulHi;
  349.   *low = ulLow;
  350.  
  351.   return ulLow;       
  352. }   
  353.