High_Res_Timer.h

Go to the documentation of this file.
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 */

Generated on Thu Nov 9 09:41:52 2006 for ACE by doxygen 1.3.6