00001 // -*- C++ -*- 00002 00003 //========================================================================== 00004 /** 00005 * @file High_Res_Timer.h 00006 * 00007 * $Id: High_Res_Timer.h 81286 2008-04-09 07:27:30Z johnnyw $ 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 #ifndef ACE_HR_SCALE_CONVERSION 00124 # define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS) 00125 #endif /* ACE_HR_SCALE_CONVERSION */ 00126 00127 /** 00128 * Sets the global_scale_factor to the value in the @a env 00129 * environment variable. Returns 0 on success, -1 on failure. 00130 * @note If @a env points to string "0" (value zero), this call will fail. 00131 * This is basically a no-op on CE because there is no concept of 00132 * environment variable on CE. 00133 */ 00134 static int get_env_global_scale_factor (const ACE_TCHAR *env 00135 = ACE_TEXT ("ACE_SCALE_FACTOR")); 00136 00137 /** 00138 * Set (and return, for info) the global scale factor by sleeping 00139 * for @a usec and counting the number of intervening clock cycles. 00140 * Average over @a iterations of @a usec each. On some platforms, 00141 * such as Pentiums, this is called automatically during the first 00142 * ACE_High_Res_Timer construction with the default parameter 00143 * values. An application can override that by calling calibrate 00144 * with any desired parameter values _prior_ to constructing the 00145 * first ACE_High_Res_Timer instance. 00146 * Beware for platforms that can change the cycle rate on the fly. 00147 */ 00148 static ACE_UINT32 calibrate (const ACE_UINT32 usec = 500000, 00149 const u_int iterations = 10); 00150 00151 /// Initialize the timer. 00152 ACE_High_Res_Timer (void); 00153 00154 /// Destructor. 00155 ~ACE_High_Res_Timer (void); 00156 00157 /// Reinitialize the timer. 00158 void reset (void); 00159 00160 /// Start timing. 00161 void start (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00162 00163 /// Stop timing. 00164 void stop (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00165 00166 /// Set @a tv to the number of microseconds elapsed. 00167 /** 00168 * Could overflow within hours on windows with emulated 64 bit int's 00169 * and a fast counter. VC++ and Borland normaly use __int64 and 00170 * so normaly don't have this problem. 00171 */ 00172 void elapsed_time (ACE_Time_Value &tv) const; 00173 00174 /// Set @a nanoseconds to the number of nanoseconds elapsed. 00175 /** 00176 * Will overflow when measuring more than 194 day's. 00177 */ 00178 void elapsed_time (ACE_hrtime_t &nanoseconds) const; 00179 00180 #if defined (ACE_HAS_POSIX_TIME) 00181 /// Returns the elapsed (stop - start) time in a struct timespec 00182 /// (sec, nsec). 00183 void elapsed_time (struct timespec &) const; 00184 #endif /* ACE_HAS_POSIX_TIME */ 00185 00186 /// Sets @a usecs to the elapsed (stop - start) time in microseconds. 00187 /** 00188 * Will overflow on windows when measuring more than appox. 2^^54 ticks. 00189 * Is still more than 48 days with a 4 Ghz counter. 00190 */ 00191 void elapsed_microseconds (ACE_hrtime_t &usecs) const; 00192 00193 /// Start incremental timing. 00194 void start_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00195 00196 /// Stop incremental timing. 00197 void stop_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME); 00198 00199 /// Set @a tv to the number of microseconds elapsed between all calls 00200 /// to start_incr and stop_incr. 00201 void elapsed_time_incr (ACE_Time_Value &tv) const; 00202 00203 /// Set <nsec> to the number of nanoseconds elapsed between all calls 00204 /// to start_incr and stop_incr. 00205 void elapsed_time_incr (ACE_hrtime_t &nanoseconds) const; 00206 00207 #if !defined (ACE_HAS_WINCE) 00208 // @@ WINCE These two functions are currently not supported on Windows CE. 00209 // However, we should probably use the handle and ACE_Log_Msg to 00210 // print out the result. 00211 /// Print total time. 00212 /// @note only use <print_total> if incremental timings had been used! 00213 void print_total (const ACE_TCHAR *message, 00214 const int iterations = 1, 00215 ACE_HANDLE handle = ACE_STDOUT) const; 00216 00217 /// Print average time. 00218 void print_ave (const ACE_TCHAR *message, 00219 const int iterations = 1, 00220 ACE_HANDLE handle = ACE_STDOUT) const; 00221 #endif /* !ACE_HAS_WINCE */ 00222 00223 /// Dump the state of an object. 00224 void dump (void) const; 00225 00226 /// Declare the dynamic allocation hooks. 00227 ACE_ALLOC_HOOK_DECLARE; 00228 00229 /** 00230 * Get the current "time" as the high resolution counter at this time. 00231 * This is intended to be useful for supplying to a ACE_Timer_Queue 00232 * as the gettimeofday function, thereby basing the timer calculations 00233 * on the high res timer rather than wall clock time. 00234 */ 00235 static ACE_Time_Value gettimeofday_hr (void); 00236 00237 /** 00238 * @deprecated THIS FUNCTION IS DEPRECATED. PLEASE USE 00239 * <ACE_OS::gettimeofday> INSTEAD! Calls <ACE_High_Res_Timer::hrtime_to_tv> 00240 * passing <ACE_OS::gethrtime>. This function can be used to parameterize 00241 * objects such as <ACE_Timer_Queue::gettimeofday>. If 00242 * <global_scale_factor_> is not set, and we're on a platform that 00243 * requires <global_scale_factor_> (e.g., Win32), 00244 * ACE_OS::gettimeofday will be used instead of <ACE_OS::gethrtime>. 00245 * This allows applications on Intel to use <High_Res_Timer> even 00246 * when <global_scale_factor> is not set. However, setting the 00247 * <global_scale_factor_> appropriately will result in the finest 00248 * resolution possible. 00249 */ 00250 static ACE_Time_Value gettimeofday (const ACE_OS::ACE_HRTimer_Op = 00251 ACE_OS::ACE_HRTIMER_GETTIME); 00252 00253 /// Converts an @a hrt to @a tv using global_scale_factor_. 00254 static void hrtime_to_tv (ACE_Time_Value &tv, 00255 const ACE_hrtime_t hrt); 00256 00257 #if defined (linux) 00258 /** 00259 * This is used to find out the Mhz of the machine for the scale 00260 * factor. If there are any problems getting it, we just return 1 00261 * (the default). 00262 */ 00263 static ACE_UINT32 get_cpuinfo (void); 00264 #endif /* defined (linux) */ 00265 00266 private: 00267 /** 00268 * For internal use: gets the high-resolution time using 00269 * <ACE_OS::gethrtime>. Except on platforms that require that the 00270 * <global_scale_factor_> be set, such as ACE_WIN32, uses the 00271 * low-resolution clock if the <global_scale_factor_> has not been 00272 * set. 00273 */ 00274 static ACE_hrtime_t gettime (const ACE_OS::ACE_HRTimer_Op = 00275 ACE_OS::ACE_HRTIMER_GETTIME); 00276 00277 /// Calculate the difference between two ACE_hrtime_t values. It is assumed 00278 /// that the end time is later than start time, so if end is a smaller 00279 /// value, the time counter has wrapped around. 00280 static ACE_hrtime_t elapsed_hrtime (const ACE_hrtime_t end, 00281 const ACE_hrtime_t start); 00282 00283 /// Starting time. 00284 ACE_hrtime_t start_; 00285 00286 /// Ending time. 00287 ACE_hrtime_t end_; 00288 00289 /// Total elapsed time. 00290 ACE_hrtime_t total_; 00291 00292 /// Start time of incremental timing. 00293 ACE_hrtime_t start_incr_; 00294 00295 /// Converts ticks to microseconds. That is, ticks / 00296 /// global_scale_factor_ == microseconds. 00297 static ACE_UINT32 global_scale_factor_; 00298 00299 /** 00300 * Indicates the status of the global scale factor, 00301 * 0 = hasn't been set 00302 * 1 = been set 00303 * -1 = HR timer not supported 00304 */ 00305 static int global_scale_factor_status_; 00306 }; 00307 00308 ACE_END_VERSIONED_NAMESPACE_DECL 00309 00310 #if defined (__ACE_INLINE__) 00311 #include "ace/High_Res_Timer.inl" 00312 #endif /* __ACE_INLINE__ */ 00313 00314 #include /**/ "ace/post.h" 00315 #endif /* ACE_HIGH_RES_TIMER_H */