High_Res_Timer.h

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

Generated on Tue Feb 2 17:18:39 2010 for ACE by  doxygen 1.4.7