3 //==========================================================================
5 * @file High_Res_Timer.h
7 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
9 //==========================================================================
11 #ifndef ACE_HIGH_RES_TIMER_H
12 #define ACE_HIGH_RES_TIMER_H
13 #include /**/ "ace/pre.h"
15 #include /**/ "ace/ACE_export.h"
17 #if !defined (ACE_LACKS_PRAGMA_ONCE)
19 #endif /* ACE_LACKS_PRAGMA_ONCE */
21 #include "ace/Basic_Types.h"
22 #include "ace/OS_NS_time.h"
23 #include "ace/Time_Value.h"
25 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
28 * @class ACE_High_Res_Timer
30 * @brief A high resolution timer class wrapper that encapsulates
31 * OS-specific high-resolution timers, such as those found on
32 * Solaris, AIX, Win32/Pentium, and VxWorks.
34 * Most of the member functions don't return values. The only
35 * reason that one would fail is if high-resolution time isn't
36 * supported on the platform. To avoid impacting performance
37 * and complicating the interface, in that case,
38 * <ACE_OS::gettimeofday> is used instead.
39 * The global scale factor is required for platforms that have
40 * high-resolution timers that return units other than
41 * microseconds, such as clock ticks. It is represented as a
42 * static u_long, can only be accessed through static methods,
43 * and is used by all instances of High Res Timer. The member
44 * functions that return or print times use the global scale
45 * factor. They divide the "time" that they get from
46 * <ACE_OS::gethrtime> by global_scale_factor_ to obtain the
47 * time in microseconds. Its units are therefore 1/microsecond.
48 * On Windows the global_scale_factor_ units are 1/millisecond.
49 * There's a macro <ACE_HR_SCALE_CONVERSION> which gives the
50 * units/second. Because it's possible that the units/second
51 * changes in the future, it's recommended to use it instead
52 * of a "hard coded" solution.
53 * Dependent on the platform and used class members, there's a
54 * maximum elapsed period before overflow (which is not checked).
55 * Look at the documentation with some members functions.
56 * On some (most?) implementations it's not recommended to measure
57 * "long" timeperiods, because the error's can accumulate fast.
58 * This is probably not a problem profiling code, but could be
59 * on if the high resolution timer class is used to initiate
60 * actions after a "long" timeout.
61 * On Solaris, a scale factor of 1000 should be used because its
62 * high-resolution timer returns nanoseconds. However, on Intel
63 * platforms, we use RDTSC which returns the number of clock
64 * ticks since system boot. For a 200MHz cpu, each clock tick
65 * is 1/200 of a microsecond; the global_scale_factor_ should
66 * therefore be 200 or 200000 if it's in unit/millisecond.
67 * On Windows ::QueryPerformanceCounter() is used, which can be a
68 * different implementation depending on the used windows HAL
69 * (Hardware Abstraction Layer). On some it uses the PC "timer chip"
70 * while it uses RDTSC on others.
71 * @note The elapsed time calculations in the print methods use
72 * ACE_hrtime_t values. Those methods do _not_ check for overflow!
73 * @note Gabe <begeddov@proaxis.com> raises this issue regarding
74 * <ACE_OS::gethrtime>: on multi-processors, the processor that
75 * you query for your @c timer.stop() value might not be the one
76 * you queried for @c timer.start(). Its not clear how much
77 * divergence there would be, if any.
78 * This issue is not mentioned in the Solaris 2.5.1 gethrtime
80 * A RDTSC NOTE: RDTSC is the Intel Pentium read-time stamp counter
81 * and is actualy a 64 bit clock cycle counter, which is increased
82 * with every cycle. It has a low overhead and can be read within
83 * 16 (pentium) or 32 (pentium II,III,...) cycles, but it doesn't
84 * serialize the processor, which could give wrong timings when
85 * profiling very short code fragments.
86 * Problematic is that some power sensitive devices
87 * (laptops for example, but probably also embedded devices),
88 * do change the cycle rate while running.
89 * Some pentiums can run on (at least) two clock frequency's.
90 * Another problem arises with multiprocessor computers, there
91 * are reports that the different RDTSC's are not always kept
93 * A windows "timer chip" NOTE: (8254-compatible real-time clock)
94 * When ::QueryPerformanceCounter() uses the 8254 it has a
95 * frequency off about 1.193 Mhz (or sometimes 3.579 Mhz?) and
96 * reading it requires some time (several thousand cycles).
98 class ACE_Export ACE_High_Res_Timer
101 #if !defined (ACE_WIN32)
102 typedef ACE_UINT32 global_scale_factor_type
;
104 typedef ACE_UINT64 global_scale_factor_type
;
108 * global_scale_factor_ is set to @a gsf. All High_Res_Timers use
109 * global_scale_factor_. This allows applications to set the scale
110 * factor just once for all High_Res_Timers. Check
111 * High_Res_Timer.cpp for the default global_scale_factors for
112 * several platforms. For many platforms (e.g., Solaris), the
113 * global_scale_factor_ is set to 1000 so that <scale_factor> need
114 * not be set. Careful, a <scale_factor> of 0 will cause division
115 * by zero exceptions.
116 * Depending on the platform its units are 1/microsecond or
117 * 1/millisecond. Use @c ACE_HR_SCALE_CONVERSION inside calculations
118 * instead a hardcoded value.
120 static void global_scale_factor (global_scale_factor_type gsf
);
122 /// Returns the global_scale_factor.
123 static global_scale_factor_type
global_scale_factor (void);
125 #ifndef ACE_HR_SCALE_CONVERSION
126 # define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS)
127 #endif /* ACE_HR_SCALE_CONVERSION */
130 * Sets the global_scale_factor to the value in the @a env
131 * environment variable. Returns 0 on success, -1 on failure.
132 * @note If @a env points to string "0" (value zero), this call will fail.
133 * This is basically a no-op on CE because there is no concept of
134 * environment variable on CE.
136 static int get_env_global_scale_factor (const ACE_TCHAR
*env
137 = ACE_TEXT ("ACE_SCALE_FACTOR"));
140 * Set (and return, for info) the global scale factor by sleeping
141 * for @a usec and counting the number of intervening clock cycles.
142 * Average over @a iterations of @a usec each. On some platforms,
143 * such as Pentiums, this is called automatically during the first
144 * ACE_High_Res_Timer construction with the default parameter
145 * values. An application can override that by calling calibrate
146 * with any desired parameter values _prior_ to constructing the
147 * first ACE_High_Res_Timer instance.
148 * Beware for platforms that can change the cycle rate on the fly.
150 static ACE_UINT32
calibrate (const ACE_UINT32 usec
= 500000,
151 const u_int iterations
= 10);
153 /// Initialize the timer.
154 ACE_High_Res_Timer (void);
157 ~ACE_High_Res_Timer (void);
159 /// Reinitialize the timer.
163 void start (const ACE_OS::ACE_HRTimer_Op
= ACE_OS::ACE_HRTIMER_GETTIME
);
166 void stop (const ACE_OS::ACE_HRTimer_Op
= ACE_OS::ACE_HRTIMER_GETTIME
);
168 /// Set @a tv to the number of microseconds elapsed.
169 void elapsed_time (ACE_Time_Value
&tv
) const;
171 /// Set @a nanoseconds to the number of nanoseconds elapsed.
173 * Will overflow when measuring more than 194 day's.
175 void elapsed_time (ACE_hrtime_t
&nanoseconds
) const;
177 #if defined (ACE_HAS_POSIX_TIME)
178 /// Returns the elapsed (stop - start) time in a struct timespec
180 void elapsed_time (struct timespec
&) const;
181 #endif /* ACE_HAS_POSIX_TIME */
183 /// Sets @a usecs to the elapsed (stop - start) time in microseconds.
185 * Will overflow on windows when measuring more than appox. 2^^54 ticks.
186 * Is still more than 48 days with a 4 Ghz counter.
188 void elapsed_microseconds (ACE_hrtime_t
&usecs
) const;
190 /// Start incremental timing.
191 void start_incr (const ACE_OS::ACE_HRTimer_Op
= ACE_OS::ACE_HRTIMER_GETTIME
);
193 /// Stop incremental timing.
194 void stop_incr (const ACE_OS::ACE_HRTimer_Op
= ACE_OS::ACE_HRTIMER_GETTIME
);
196 /// Set @a tv to the number of microseconds elapsed between all calls
197 /// to start_incr and stop_incr.
198 void elapsed_time_incr (ACE_Time_Value
&tv
) const;
200 /// Set @a nanoseconds to the number of nanoseconds elapsed between all calls
201 /// to start_incr and stop_incr.
202 void elapsed_time_incr (ACE_hrtime_t
&nanoseconds
) const;
204 /// Print total time.
205 /// @note only use @c print_total if incremental timings had been used!
206 void print_total (const ACE_TCHAR
*message
,
207 const int iterations
= 1,
208 ACE_HANDLE handle
= ACE_STDOUT
) const;
210 /// Print average time.
211 void print_ave (const ACE_TCHAR
*message
,
212 const int iterations
= 1,
213 ACE_HANDLE handle
= ACE_STDOUT
) const;
215 /// Dump the state of an object.
216 void dump (void) const;
218 /// Declare the dynamic allocation hooks.
219 ACE_ALLOC_HOOK_DECLARE
;
222 * Get the current "time" as the high resolution counter at this time.
223 * This is intended to be useful for supplying to a ACE_Timer_Queue
224 * as the gettimeofday function, thereby basing the timer calculations
225 * on the high res timer rather than wall clock time.
227 static ACE_Time_Value
gettimeofday_hr (void);
230 * @deprecated THIS FUNCTION IS DEPRECATED. PLEASE USE
231 * <ACE_OS::gettimeofday> INSTEAD! Calls <ACE_High_Res_Timer::hrtime_to_tv>
232 * passing <ACE_OS::gethrtime>. This function can be used to parameterize
233 * objects such as <ACE_Timer_Queue::gettimeofday>. If
234 * <global_scale_factor_> is not set, and we're on a platform that
235 * requires <global_scale_factor_> (e.g., Win32),
236 * ACE_OS::gettimeofday will be used instead of <ACE_OS::gethrtime>.
237 * This allows applications on Intel to use <High_Res_Timer> even
238 * when <global_scale_factor> is not set. However, setting the
239 * <global_scale_factor_> appropriately will result in the finest
240 * resolution possible.
242 static ACE_Time_Value
gettimeofday (const ACE_OS::ACE_HRTimer_Op
=
243 ACE_OS::ACE_HRTIMER_GETTIME
);
245 /// Converts an @a hrt to @a tv using global_scale_factor_.
246 static void hrtime_to_tv (ACE_Time_Value
&tv
,
247 const ACE_hrtime_t hrt
);
249 #if defined (ACE_LINUX) && !defined (ACE_LACKS_SSCANF)
251 * This is used to find out the Mhz of the machine for the scale
252 * factor. If there are any problems getting it, we just return 1
255 static ACE_UINT32
get_cpuinfo (void);
256 #endif /* defined (ACE_LINUX) && !ACE_LACKS_SSCANF */
260 * For internal use: gets the high-resolution time using
261 * <ACE_OS::gethrtime>. Except on platforms that require that the
262 * <global_scale_factor_> be set, such as ACE_WIN32, uses the
263 * low-resolution clock if the <global_scale_factor_> has not been
266 static ACE_hrtime_t
gettime (const ACE_OS::ACE_HRTimer_Op
=
267 ACE_OS::ACE_HRTIMER_GETTIME
);
269 /// Calculate the difference between two ACE_hrtime_t values. It is assumed
270 /// that the end time is later than start time, so if end is a smaller
271 /// value, the time counter has wrapped around.
272 static ACE_hrtime_t
elapsed_hrtime (const ACE_hrtime_t end
,
273 const ACE_hrtime_t start
);
281 /// Total elapsed time.
284 /// Start time of incremental timing.
285 ACE_hrtime_t start_incr_
;
287 /// Converts ticks to microseconds. That is, ticks /
288 /// global_scale_factor_ == microseconds.
289 static global_scale_factor_type global_scale_factor_
;
292 * Indicates the status of the global scale factor,
293 * 0 = hasn't been set
295 * -1 = HR timer not supported
297 static int global_scale_factor_status_
;
300 ACE_END_VERSIONED_NAMESPACE_DECL
302 #if defined (__ACE_INLINE__)
303 #include "ace/High_Res_Timer.inl"
304 #endif /* __ACE_INLINE__ */
306 #include /**/ "ace/post.h"
307 #endif /* ACE_HIGH_RES_TIMER_H */