Azinix

timing.h

Go to the documentation of this file.
00001 /** \file timing.h
00002 
00003   \brief Utilities for performing timing
00004 
00005 */
00006 
00007 /**AutomaticStart*************************************************************/
00008 
00009 /*---------------------------------------------------------------------------*/
00010 /* Function prototypes                                                       */
00011 /*---------------------------------------------------------------------------*/
00012 
00013 /**AutomaticEnd***************************************************************/
00014 
00015 
00016 #ifndef _TIMING
00017 #define _TIMING
00018 
00019 #ifdef __cplusplus
00020 extern "C" {
00021 #endif
00022 
00023 #include <stdio.h>
00024 #include <ctype.h>
00025 #include <math.h>
00026 
00027 #include <assert.h>
00028 #include <time.h>
00029 
00030 
00031 /**
00032   * \brief  An encapsulation of a pair of u_int32_t's used to manipulate times
00033   * 
00034   * An encapsulation of a pair of u_int32_t's used to manipulate times
00035   * 
00036   */
00037 
00038 
00039 struct util_timing_t
00040 {
00041   u_int32_t high;
00042   u_int32_t low;
00043 };
00044 
00045 typedef struct util_timing_t util_timing_t;
00046 
00047 
00048 extern double PROCESSOR_FREQUENCY;
00049 
00050 /* From /usr/src/linux-2.4.20-8/include/asm-i386/msr.h
00051  *
00052  * Useful for very precise timing
00053  * 
00054  * Access to machine-specific registers (available on 586 and better only)
00055  * Note: the rd* operations modify the parameters directly (without using
00056  * pointer indirection), this allows gcc to optimize better
00057  *
00058  */
00059 
00060 #define rdmsr(msr,val1,val2) \
00061      __asm__ __volatile__("rdmsr" \
00062                           : "=a" (val1), "=d" (val2) : "c" (msr))
00063 
00064 #define wrmsr(msr,val1,val2) \
00065      __asm__ __volatile__("wrmsr" \
00066                           : /* no outputs */ \
00067                           : "c" (msr), "a" (val1), "d" (val2))
00068 
00069 #define rdtsc(low,high) \
00070      __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
00071 
00072 #define rdtscl(low) \
00073      __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
00074 
00075 #define rdtscll(val) \
00076      __asm__ __volatile__("rdtsc" : "=A" (val))
00077 
00078 #define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
00079 
00080 #define rdpmc(counter,low,high) \
00081      __asm__ __volatile__("rdpmc" \
00082                           : "=a" (low), "=d" (high) \
00083                           : "c" (counter))
00084 
00085 
00086 /**
00087   * \brief Set the low and high fields in the struct based on current time
00088   */
00089 
00090 static inline void
00091 util_timing_set (util_timing_t * time)
00092 {
00093   rdtsc (time->low, time->high);
00094 }
00095 
00096 
00097 /**
00098   * \brief Form the difference arg1 - arg2 of the times denoted by arg1 and arg2,
00099   *     arg1 is assumed to be larger than arg2
00100   */
00101 
00102 static inline util_timing_t
00103 util_timing_diff (util_timing_t arg1, util_timing_t arg2)
00104 {
00105   util_timing_t result;
00106 
00107   if (arg1.low >= arg2.low)
00108     {
00109       // ( 5, 6 ) - ( 4, 5 ) = ( 1, 1 ) 
00110       // ( 5, 5 ) - ( 4, 5 ) = ( 1, 0 ) 
00111       result.low = arg1.low - arg2.low;
00112       result.high = arg1.high - arg2.high;
00113     }
00114   else
00115     {
00116       // ( 5, 5 ) - ( 4, 6 ) = ( 0, 9 ) 
00117       assert (arg1.high > arg2.high);
00118       result.low = (~((u_int32_t) (0)) - arg2.low) + arg1.low;
00119       result.high = arg1.high - arg2.high - 1;
00120     }
00121   return result;
00122 }
00123 
00124 
00125 /**
00126   * \brief  Return 64-bit time in seconds
00127   * 
00128   */
00129 
00130 static inline double
00131 util_timing_secs (util_timing_t time)
00132 {
00133   double low = (double) time.low;
00134   double high = (double) time.high;
00135 
00136   double maxInt = 1.0 + (double) (~((u_int32_t) 0));
00137   double tick = 1.0 / PROCESSOR_FREQUENCY;
00138 
00139   double delta = (tick) * ((low) + maxInt * high);
00140 
00141   return delta;
00142 }
00143 
00144 
00145 /**
00146   * \brief Return the current time, in seconds
00147   */
00148 
00149 static inline double
00150 util_timing_now ()
00151 {
00152   util_timing_t now;
00153   double result;
00154   util_timing_set (&now);
00155   result = util_timing_secs (now);
00156 
00157   return result;
00158 }
00159 
00160 
00161 /**
00162   * \brief  Check if arg1 reps a lesser time than arg2
00163   * 
00164   */
00165 
00166 static inline int
00167 util_timing_compare (util_timing_t arg1, util_timing_t arg2)
00168 {
00169   if (arg1.high < arg2.high)
00170     {
00171       return 1;
00172     }
00173   else if ((arg1.high == arg2.high) && (arg1.low < arg2.low))
00174     {
00175       return 1;
00176     }
00177   else
00178     {
00179       return 0;
00180     }
00181 }
00182 
00183 
00184 /**
00185   * \brief  Convert a time specifed as a double to an rdtsc pair
00186   * 
00187   */
00188 
00189 static inline util_timing_t
00190 util_timing_pair (double time)
00191 {
00192   util_timing_t result;
00193   double maxInt = 1.0 + (double) (~((u_int32_t) 0));
00194   double tick = 1.0 / PROCESSOR_FREQUENCY;
00195 
00196   double tickTime = time / tick;
00197 
00198   double hightime = floor (tickTime / maxInt);
00199   double lowtime = tickTime - (hightime * maxInt);
00200 
00201   result.low = lowtime;
00202   result.high = hightime;
00203 
00204   return result;
00205 }
00206 
00207 /**
00208   * \brief Pause for pauseTime
00209   */
00210 
00211 static inline void
00212 util_timing_pause (util_timing_t pauseTime)
00213 {
00214   util_timing_t startTime, currentTime, diffTime;
00215   if ((pauseTime.low == 0) && (pauseTime.high == 0))
00216     {
00217       return;
00218     }
00219   util_timing_set (&startTime);
00220 
00221   while (1)
00222     {
00223       util_timing_set (&currentTime);
00224       diffTime = util_timing_diff (currentTime, startTime);
00225       // check if pauseTime is less than diffTime
00226       if (util_timing_compare (pauseTime, diffTime))
00227     {
00228       return;
00229     }
00230     }
00231 }
00232 
00233 
00234 /**
00235   * \brief Pause for T seconds.
00236   */
00237 
00238 static inline void
00239 util_timing_pause_secs (double T)
00240 {
00241   util_timing_t pauseTime = util_timing_pair (T);
00242   util_timing_pause (pauseTime);
00243 }
00244 
00245 #ifdef __cplusplus
00246 }
00247 #endif
00248 
00249 #endif /* _TIMING */