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