Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

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

Generated on Mon Jun 16 11:19:52 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002