00001 // -*- C++ -*- 00002 00003 //========================================================================== 00004 /** 00005 * @file High_Res_Timer.h 00006 * 00007 * High_Res_Timer.h,v 4.65 2006/01/25 19:50:07 jwillemsen Exp 00008 * 00009 * @author Douglas C. Schmidt <schmidt@cs.wustl.edu> 00010 */ 00011 //========================================================================== 00012 00013 #ifndef ACE_HIGH_RES_TIMER_H 00014 #define ACE_HIGH_RES_TIMER_H 00015 #include /**/ "ace/pre.h" 00016 00017 #include "ace/ACE_export.h" 00018 00019 #if !defined (ACE_LACKS_PRAGMA_ONCE) 00020 # pragma once 00021 #endif /* ACE_LACKS_PRAGMA_ONCE */ 00022 00023 #include "ace/Basic_Types.h" 00024 #include "ace/OS_NS_time.h" 00025 #include "ace/Time_Value.h" 00026 00027 ACE_BEGIN_VERSIONED_NAMESPACE_DECL 00028 00029 /** 00030 * @class ACE_High_Res_Timer 00031 * 00032 * @brief A high resolution timer class wrapper that encapsulates 00033 * OS-specific high-resolution timers, such as those found on 00034 * Solaris, AIX, Win32/Pentium, and VxWorks. 00035 * 00036 * Most of the member functions don't return values. The only 00037 * reason that one would fail is if high-resolution time isn't 00038 * supported on the platform. To avoid impacting performance 00039 * and complicating the interface, in that case, 00040 * <ACE_OS::gettimeofday> is used instead. 00041 * The global scale factor is required for platforms that have 00042 * high-resolution timers that return units other than 00043 * microseconds, such as clock ticks. It is represented as a 00044 * static u_long, can only be accessed through static methods, 00045 * and is used by all instances of High Res Timer. The member 00046 * functions that return or print times use the global scale 00047 * factor. They divide the "time" that they get from 00048 * <ACE_OS::gethrtime> by global_scale_factor_ to obtain the 00049 * time in microseconds. Its units are therefore 1/microsecond. 00050 * On Windows the global_scale_factor_ units are 1/millisecond. 00051 * There's a macro <ACE_HR_SCALE_CONVERSION> which gives the 00052 * units/second. Because it's possible that the units/second 00053 * changes in the future, it's recommended to use it instead 00054 * of a "hard coded" solution. 00055 * Dependend on the platform and used class members, there's a 00056 * maximum elapsed period before overflow (which is not checked). 00057 * Look at the documentation with some members functions. 00058 * On some (most?) implementations it's not recommended to measure 00059 * "long" timeperiods, because the error's can accumulate fast. 00060 * This is probably not a problem profiling code, but could be 00061 * on if the high resolution timer class is used to initiate 00062 * actions after a "long" timeout. 00063 * On Solaris, a scale factor of 1000 should be used because its 00064 * high-resolution timer returns nanoseconds. However, on Intel 00065 * platforms, we use RDTSC which returns the number of clock 00066 * ticks since system boot. For a 200MHz cpu, each clock tick 00067 * is 1/200 of a microsecond; the global_scale_factor_ should 00068 * therefore be 200 or 200000 if it's in unit/millisecond. 00069 * On Windows ::QueryPerformanceCounter() is used, which can be a 00070 * different implementation depending on the used windows HAL 00071 * (Hardware Abstraction Layer). On some it uses the PC "timer chip" 00072 * while it uses RDTSC on others. 00073 * @note The elapsed time calculations in the print methods use 00074 * ACE_hrtime_t values. Those methods do _not_ check for overflow! 00075 * @note Gabe <begeddov@proaxis.com> raises this issue regarding 00076 * <ACE_OS::gethrtime>: on multi-processors, the processor that 00077 * you query for your <timer.stop> value might not be the one 00078 * you queried for <timer.start>. Its not clear how much 00079 * divergence there would be, if any. 00080 * This issue is not mentioned in the Solaris 2.5.1 gethrtime 00081 * man page. 00082 * A RDTSC NOTE: RDTSC is the Intel Pentium read-time stamp counter 00083 * and is actualy a 64 bit clock cycle counter, which is increased 00084 * with every cycle. It has a low overhead and can be read within 00085 * 16 (pentium) or 32 (pentium II,III,...) cycles, but it doesn't 00086 * serialize the processor, which could give wrong timings when 00087 * profiling very short code fragments. 00088 * Problematic is that some power sensitive devices 00089 * (laptops for example, but probably also embedded devices), 00090 * do change the cycle rate while running. 00091 * Some pentiums can run on (at least) two clock frequency's. 00092 * Another problem arises with multiprocessor computers, there 00093 * are reports that the different RDTSC's are not always kept 00094 * in sync. 00095 * A windows "timer chip" NOTE: (8254-compatible real-time clock) 00096 * When ::QueryPerformanceCounter() uses the 8254 it has a 00097 * frequency off about 1.193 Mhz (or sometimes 3.579 Mhz?) and 00098 * reading it requires some time (several thousand cycles). 00099 */ 00100 class ACE_Export ACE_High_Res_Timer 00101 { 00102 public: 00103 // = Initialization method. 00104 00105 /** 00106 * global_scale_factor_ is set to @a gsf. All High_Res_Timers use 00107 * global_scale_factor_. This allows applications to set the scale 00108 * factor just once for all High_Res_Timers. Check 00109 * High_Res_Timer.cpp for the default global_scale_factors for 00110 * several platforms. For many platforms (e.g., Solaris), the 00111 * global_scale_factor_ is set to 1000 so that <scale_factor> need 00112 * not be set. Careful, a <scale_factor> of 0 will cause division 00113 * by zero exceptions. 00114 * Depending on the platform its units are 1/microsecond or 00115 * 1/millisecond. Use <ACE_HR_SCALE_CONVERSION> inside calculations 00116 * instead a hardcoded value. 00117 */ 00118 static void global_scale_factor (ACE_UINT32 gsf); 00119 00120 /// Returns the global_scale_factor. 00121 static ACE_UINT32 global_scale_factor (void); 00122 00123 // On Win32, QueryPerformanceFrequency is used as a base for the global 00124 // scale factor. The value this returns is often too small to be usefully 00125 // converted to "ticks"/second - it loses unacceptably high levels of 00126 // precision. So on Win32, global_scale_factor_ is in ticks/msec, not 00127 // ticks/usec as on all others. 00128 #if defined (ACE_WIN32) 00129 # define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_MSECS) 00130 #else 00131 # define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS) 00132 #endif /* ACE_WIN32 */ 00133 00134 /** 00135 * Sets the global_scale_factor to the value in the <env> 00136 * environment variable. Returns 0 on success, -1 on failure. 00137 * @note If @a env points to string "0" (value zero), this call will fail. 00138 * This is basically a no-op on CE because there is no concept of 00139 * environment variable on CE. 00140 */ 00141 static int get_env_global_scale_factor (const ACE_TCHAR *env 00142 = ACE_LIB_TEXT ("ACE_SCALE_FACTOR")); 00143 00144 /** 00145 * Set (and return, for info) the global scale factor by sleeping 00146 * for @a usec and counting the number of intervening clock cycles. 00147 * Average over @a iterations of @a usec each. On some platforms, 00148 * such as Pentiums, this is called automatically during the first 00149 * ACE_High_Res_Timer construction with the default parameter 00150 * values. An application can override that by calling calibrate 00151 * with any desired parameter values _prior_ to constructing the 00152 * first ACE_High_Res_Timer instance. 00153 * Beware for platforms that can change the cycle rate on the fly. 00154 */ 00155 static ACE_UINT32 calibrate (const ACE_UINT32 usec = 500000, 00156 const u_int iterations = 10); 00157 00158 /// Initialize the timer. 00159 ACE_High_Res_Timer (void); 00160 00161 /// Destructor. 00162 ~ACE_High_Res_Timer (void); 00163 00164 /// Reinitialize the timer. 00165 void reset (void); 00166 00167 /// Start timing. 00168 void start (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00169 00170 /// Stop timing. 00171 void stop (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00172 00173 /// Set @a tv to the number of microseconds elapsed. 00174 /** 00175 * Could overflow within hours on windows with emulated 64 bit int's 00176 * and a fast counter. VC++ and Borland normaly use __int64 and 00177 * so normaly don't have this problem. 00178 */ 00179 void elapsed_time (ACE_Time_Value &tv) const; 00180 00181 /// Set @a nanoseconds to the number of nanoseconds elapsed. 00182 /** 00183 * Will overflow when measuring more than 194 day's. 00184 */ 00185 void elapsed_time (ACE_hrtime_t &nanoseconds) const; 00186 00187 #if defined (ACE_HAS_POSIX_TIME) 00188 /// Returns the elapsed (stop - start) time in a struct timespec 00189 /// (sec, nsec). 00190 void elapsed_time (struct timespec &) const; 00191 #endif /* ACE_HAS_POSIX_TIME */ 00192 00193 /// Sets @a usecs to the elapsed (stop - start) time in microseconds. 00194 /** 00195 * Will overflow on windows when measuring more than appox. 2^^54 ticks. 00196 * Is still more than 48 days with a 4 Ghz counter. 00197 */ 00198 void elapsed_microseconds (ACE_hrtime_t &usecs) const; 00199 00200 /// Start incremental timing. 00201 void start_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00202 00203 /// Stop incremental timing. 00204 void stop_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00205 00206 /// Set @a tv to the number of microseconds elapsed between all calls 00207 /// to start_incr and stop_incr. 00208 void elapsed_time_incr (ACE_Time_Value &tv) const; 00209 00210 /// Set <nsec> to the number of nanoseconds elapsed between all calls 00211 /// to start_incr and stop_incr. 00212 void elapsed_time_incr (ACE_hrtime_t &nanoseconds) const; 00213 00214 #if !defined (ACE_HAS_WINCE) 00215 // @@ WINCE These two functions are currently not supported on Windows CE. 00216 // However, we should probably use the handle and ACE_Log_Msg to 00217 // print out the result. 00218 /// Print total time. 00219 /// @note only use <print_total> if incremental timings had been used! 00220 void print_total (const ACE_TCHAR *message, 00221 const int iterations = 1, 00222 ACE_HANDLE handle = ACE_STDOUT) const; 00223 00224 /// Print average time. 00225 void print_ave (const ACE_TCHAR *message, 00226 const int iterations = 1, 00227 ACE_HANDLE handle = ACE_STDOUT) const; 00228 #endif /* !ACE_HAS_WINCE */ 00229 00230 /// Dump the state of an object. 00231 void dump (void) const; 00232 00233 /// Declare the dynamic allocation hooks. 00234 ACE_ALLOC_HOOK_DECLARE; 00235 00236 /** 00237 * Get the current "time" as the high resolution counter at this time. 00238 * This is intended to be useful for supplying to a ACE_Timer_Queue 00239 * as the gettimeofday function, thereby basing the timer calculations 00240 * on the high res timer rather than wall clock time. 00241 */ 00242 static ACE_Time_Value gettimeofday_hr (void); 00243 00244 /** 00245 * @deprecated THIS FUNCTION IS DEPRECATED. PLEASE USE 00246 * <ACE_OS::gettimeofday> INSTEAD! Calls <ACE_High_Res_Timer::hrtime_to_tv> 00247 * passing <ACE_OS::gethrtime>. This function can be used to parameterize 00248 * objects such as <ACE_Timer_Queue::gettimeofday>. If 00249 * <global_scale_factor_> is not set, and we're on a platform that 00250 * requires <global_scale_factor_> (e.g., Win32), 00251 * ACE_OS::gettimeofday will be used instead of <ACE_OS::gethrtime>. 00252 * This allows applications on Intel to use <High_Res_Timer> even 00253 * when <global_scale_factor> is not set. However, setting the 00254 * <global_scale_factor_> appropriately will result in the finest 00255 * resolution possible. 00256 */ 00257 static ACE_Time_Value gettimeofday (const ACE_OS::ACE_HRTimer_Op = 00258 ACE_OS::ACE_HRTIMER_GETTIME); 00259 00260 /// Converts an <hrt> to <tv> using global_scale_factor_. 00261 static void hrtime_to_tv (ACE_Time_Value &tv, 00262 const ACE_hrtime_t hrt); 00263 00264 #if defined (linux) 00265 /** 00266 * This is used to find out the Mhz of the machine for the scale 00267 * factor. If there are any problems getting it, we just return 1 00268 * (the default). 00269 */ 00270 static ACE_UINT32 get_cpuinfo (void); 00271 #endif /* defined (linux) */ 00272 00273 private: 00274 /** 00275 * For internal use: gets the high-resolution time using 00276 * <ACE_OS::gethrtime>. Except on platforms that require that the 00277 * <global_scale_factor_> be set, such as ACE_WIN32, uses the 00278 * low-resolution clock if the <global_scale_factor_> has not been 00279 * set. 00280 */ 00281 static ACE_hrtime_t gettime (const ACE_OS::ACE_HRTimer_Op = 00282 ACE_OS::ACE_HRTIMER_GETTIME); 00283 00284 /// Calculate the difference between two ACE_hrtime_t values. It is assumed 00285 /// that the end time is later than start time, so if end is a smaller 00286 /// value, the time counter has wrapped around. 00287 static ACE_hrtime_t elapsed_hrtime (const ACE_hrtime_t end, 00288 const ACE_hrtime_t start); 00289 00290 /// Starting time. 00291 ACE_hrtime_t start_; 00292 00293 /// Ending time. 00294 ACE_hrtime_t end_; 00295 00296 /// Total elapsed time. 00297 ACE_hrtime_t total_; 00298 00299 /// Start time of incremental timing. 00300 ACE_hrtime_t start_incr_; 00301 00302 /// Converts ticks to microseconds. That is, ticks / 00303 /// global_scale_factor_ == microseconds. 00304 static ACE_UINT32 global_scale_factor_; 00305 00306 /** 00307 * Indicates the status of the global scale factor, 00308 * 0 = hasn't been set 00309 * 1 = been set 00310 * -1 = HR timer not supported 00311 */ 00312 static int global_scale_factor_status_; 00313 }; 00314 00315 ACE_END_VERSIONED_NAMESPACE_DECL 00316 00317 #if defined (__ACE_INLINE__) 00318 #include "ace/High_Res_Timer.inl" 00319 #endif /* __ACE_INLINE__ */ 00320 00321 #include /**/ "ace/post.h" 00322 #endif /* ACE_HIGH_RES_TIMER_H */