Document return values
[ACE_TAO.git] / ACE / ace / High_Res_Timer.h
blob6c94f3566d3eb1263697bda5e0268bc359c39021
1 // -*- C++ -*-
3 //==========================================================================
4 /**
5 * @file High_Res_Timer.h
7 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
8 */
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)
18 # 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
27 /**
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 * 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 Intel platforms, we use RDTSC which returns the number of clock
62 * ticks since system boot. For a 200MHz cpu, each clock tick
63 * is 1/200 of a microsecond; the global_scale_factor_ should
64 * therefore be 200 or 200000 if it's in unit/millisecond.
65 * On Windows ::QueryPerformanceCounter() is used, which can be a
66 * different implementation depending on the used windows HAL
67 * (Hardware Abstraction Layer). On some it uses the PC "timer chip"
68 * while it uses RDTSC on others.
69 * @note The elapsed time calculations in the print methods use
70 * ACE_hrtime_t values. Those methods do _not_ check for overflow!
71 * @note Gabe <begeddov@proaxis.com> raises this issue regarding
72 * <ACE_OS::gethrtime>: on multi-processors, the processor that
73 * you query for your @c timer.stop() value might not be the one
74 * you queried for @c timer.start(). Its not clear how much
75 * divergence there would be, if any.
76 * A RDTSC NOTE: RDTSC is the Intel Pentium read-time stamp counter
77 * and is actualy a 64 bit clock cycle counter, which is increased
78 * with every cycle. It has a low overhead and can be read within
79 * 16 (pentium) or 32 (pentium II,III,...) cycles, but it doesn't
80 * serialize the processor, which could give wrong timings when
81 * profiling very short code fragments.
82 * Problematic is that some power sensitive devices
83 * (laptops for example, but probably also embedded devices),
84 * do change the cycle rate while running.
85 * Some pentiums can run on (at least) two clock frequency's.
86 * Another problem arises with multiprocessor computers, there
87 * are reports that the different RDTSC's are not always kept
88 * in sync.
89 * A windows "timer chip" NOTE: (8254-compatible real-time clock)
90 * When ::QueryPerformanceCounter() uses the 8254 it has a
91 * frequency off about 1.193 Mhz (or sometimes 3.579 Mhz?) and
92 * reading it requires some time (several thousand cycles).
94 class ACE_Export ACE_High_Res_Timer
96 public:
97 #if !defined (ACE_WIN32)
98 typedef ACE_UINT32 global_scale_factor_type;
99 #else
100 typedef ACE_UINT64 global_scale_factor_type;
101 #endif
104 * global_scale_factor_ is set to @a gsf. All High_Res_Timers use
105 * global_scale_factor_. This allows applications to set the scale
106 * factor just once for all High_Res_Timers. Check
107 * High_Res_Timer.cpp for the default global_scale_factors for
108 * several platforms. For many platforms the
109 * global_scale_factor_ is set to 1000 so that <scale_factor> need
110 * not be set. Careful, a <scale_factor> of 0 will cause division
111 * by zero exceptions.
112 * Depending on the platform its units are 1/microsecond or
113 * 1/millisecond. Use @c ACE_HR_SCALE_CONVERSION inside calculations
114 * instead a hardcoded value.
116 static void global_scale_factor (global_scale_factor_type gsf);
118 /// Returns the global_scale_factor.
119 static global_scale_factor_type global_scale_factor ();
121 #ifndef ACE_HR_SCALE_CONVERSION
122 # define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS)
123 #endif /* ACE_HR_SCALE_CONVERSION */
126 * Sets the global_scale_factor to the value in the @a env
127 * environment variable. Returns 0 on success, -1 on failure.
128 * @note If @a env points to string "0" (value zero), this call will fail.
129 * This is basically a no-op on CE because there is no concept of
130 * environment variable on CE.
132 static int get_env_global_scale_factor (const ACE_TCHAR *env
133 = ACE_TEXT ("ACE_SCALE_FACTOR"));
136 * Set (and return, for info) the global scale factor by sleeping
137 * for @a usec and counting the number of intervening clock cycles.
138 * Average over @a iterations of @a usec each. On some platforms,
139 * such as Pentiums, this is called automatically during the first
140 * ACE_High_Res_Timer construction with the default parameter
141 * values. An application can override that by calling calibrate
142 * with any desired parameter values _prior_ to constructing the
143 * first ACE_High_Res_Timer instance.
144 * Beware for platforms that can change the cycle rate on the fly.
146 static ACE_UINT32 calibrate (const ACE_UINT32 usec = 500000,
147 const u_int iterations = 10);
149 /// Initialize the timer.
150 ACE_High_Res_Timer ();
152 /// Destructor.
153 ~ACE_High_Res_Timer ();
155 /// Reinitialize the timer.
156 void reset ();
158 /// Start timing.
159 void start (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
161 /// Stop timing.
162 void stop (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
164 /// Set @a tv to the number of microseconds elapsed.
165 void elapsed_time (ACE_Time_Value &tv) const;
167 /// Set @a nanoseconds to the number of nanoseconds elapsed.
169 * Will overflow when measuring more than 194 day's.
171 void elapsed_time (ACE_hrtime_t &nanoseconds) const;
173 #if defined (ACE_HAS_POSIX_TIME)
174 /// Returns the elapsed (stop - start) time in a struct timespec
175 /// (sec, nsec).
176 void elapsed_time (struct timespec &) const;
177 #endif /* ACE_HAS_POSIX_TIME */
179 /// Sets @a usecs to the elapsed (stop - start) time in microseconds.
181 * Will overflow on windows when measuring more than appox. 2^^54 ticks.
182 * Is still more than 48 days with a 4 Ghz counter.
184 void elapsed_microseconds (ACE_hrtime_t &usecs) const;
186 /// Start incremental timing.
187 void start_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
189 /// Stop incremental timing.
190 void stop_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);
192 /// Set @a tv to the number of microseconds elapsed between all calls
193 /// to start_incr and stop_incr.
194 void elapsed_time_incr (ACE_Time_Value &tv) const;
196 /// Set @a nanoseconds to the number of nanoseconds elapsed between all calls
197 /// to start_incr and stop_incr.
198 void elapsed_time_incr (ACE_hrtime_t &nanoseconds) const;
200 /// Print total time.
201 /// @note only use @c print_total if incremental timings had been used!
202 void print_total (const ACE_TCHAR *message,
203 const int iterations = 1,
204 ACE_HANDLE handle = ACE_STDOUT) const;
206 /// Print average time.
207 void print_ave (const ACE_TCHAR *message,
208 const int iterations = 1,
209 ACE_HANDLE handle = ACE_STDOUT) const;
211 /// Dump the state of an object.
212 void dump () const;
214 /// Declare the dynamic allocation hooks.
215 ACE_ALLOC_HOOK_DECLARE;
218 * Get the current "time" as the high resolution counter at this time.
219 * This is intended to be useful for supplying to a ACE_Timer_Queue
220 * as the gettimeofday function, thereby basing the timer calculations
221 * on the high res timer rather than wall clock time.
223 static ACE_Time_Value gettimeofday_hr ();
226 * @deprecated THIS FUNCTION IS DEPRECATED. PLEASE USE
227 * <ACE_OS::gettimeofday> INSTEAD! Calls <ACE_High_Res_Timer::hrtime_to_tv>
228 * passing <ACE_OS::gethrtime>. This function can be used to parameterize
229 * objects such as <ACE_Timer_Queue::gettimeofday>. If
230 * <global_scale_factor_> is not set, and we're on a platform that
231 * requires <global_scale_factor_> (e.g., Win32),
232 * ACE_OS::gettimeofday will be used instead of <ACE_OS::gethrtime>.
233 * This allows applications on Intel to use <High_Res_Timer> even
234 * when <global_scale_factor> is not set. However, setting the
235 * <global_scale_factor_> appropriately will result in the finest
236 * resolution possible.
238 static ACE_Time_Value gettimeofday (const ACE_OS::ACE_HRTimer_Op =
239 ACE_OS::ACE_HRTIMER_GETTIME);
241 /// Converts an @a hrt to @a tv using global_scale_factor_.
242 static void hrtime_to_tv (ACE_Time_Value &tv,
243 const ACE_hrtime_t hrt);
245 #if defined (ACE_LINUX) && !defined (ACE_LACKS_SSCANF)
247 * This is used to find out the Mhz of the machine for the scale
248 * factor. If there are any problems getting it, we just return 1
249 * (the default).
251 static ACE_UINT32 get_cpuinfo ();
252 #endif /* defined (ACE_LINUX) && !ACE_LACKS_SSCANF */
254 private:
256 * For internal use: gets the high-resolution time using
257 * <ACE_OS::gethrtime>. Except on platforms that require that the
258 * <global_scale_factor_> be set, such as ACE_WIN32, uses the
259 * low-resolution clock if the <global_scale_factor_> has not been
260 * set.
262 static ACE_hrtime_t gettime (const ACE_OS::ACE_HRTimer_Op =
263 ACE_OS::ACE_HRTIMER_GETTIME);
265 /// Calculate the difference between two ACE_hrtime_t values. It is assumed
266 /// that the end time is later than start time, so if end is a smaller
267 /// value, the time counter has wrapped around.
268 static ACE_hrtime_t elapsed_hrtime (const ACE_hrtime_t end,
269 const ACE_hrtime_t start);
271 /// Starting time.
272 ACE_hrtime_t start_;
274 /// Ending time.
275 ACE_hrtime_t end_;
277 /// Total elapsed time.
278 ACE_hrtime_t total_;
280 /// Start time of incremental timing.
281 ACE_hrtime_t start_incr_;
283 /// Converts ticks to microseconds. That is, ticks /
284 /// global_scale_factor_ == microseconds.
285 static global_scale_factor_type global_scale_factor_;
288 * Indicates the status of the global scale factor,
289 * 0 = hasn't been set
290 * 1 = been set
291 * -1 = HR timer not supported
293 static int global_scale_factor_status_;
296 ACE_END_VERSIONED_NAMESPACE_DECL
298 #if defined (__ACE_INLINE__)
299 #include "ace/High_Res_Timer.inl"
300 #endif /* __ACE_INLINE__ */
302 #include /**/ "ace/post.h"
303 #endif /* ACE_HIGH_RES_TIMER_H */