summaryrefslogtreecommitdiff
path: root/ace/High_Res_Timer.h
blob: 19626a7d298b5a955880acb4d3cabb006c58a096 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/* -*- C++ -*- */

//=============================================================================
/**
 *  @file    High_Res_Timer.h
 *
 *  $Id$
 *
 *  @author Doug Schmidt
 */
//=============================================================================


#ifndef ACE_HIGH_RES_TIMER_H
#define ACE_HIGH_RES_TIMER_H
#include "ace/pre.h"

#include "ace/ACE.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

/**
 * @class ACE_High_Res_Timer
 *
 * @brief A high resolution timer class wrapper that encapsulates
 * OS-specific high-resolution timers, such as those found on
 * Solaris, AIX, Win32/Pentium, and VxWorks.
 *
 * Most of the member functions don't return values.  The only
 * reason that one would fail is if high-resolution time isn't
 * supported on the platform.  To avoid impacting performance
 * and complicating the interface, in that case,
 * <ACE_OS::gettimeofday> is used instead.
 * The global scale factor is required for platforms that have
 * high-resolution timers that return units other than
 * microseconds, such as clock ticks.  It is represented as a
 * static u_long, can only be accessed through static methods,
 * and is used by all instances of High Res Timer.  The member
 * functions that return or print times use the global scale
 * factor.  They divide the "time" that they get from
 * <ACE_OS::gethrtime> by global_scale_factor_ to obtain the
 * time in microseconds.  Its units are therefore 1/microsecond.
 * On Solaris, a scale factor of 1000 should be used because its
 * high-resolution timer returns nanoseconds.  However, on Intel
 * platforms, we use RDTSC which returns the number of clock
 * ticks since system boot.  For a 200MHz cpu, each clock tick
 * is 1/200 of a microsecond; the global_scale_factor_ should
 * therefore be 200.
 * NOTE:  the elapsed time calculations in the print methods use
 * ACE_hrtime_t values.  Those methods do _not_ check for overflow!
 * NOTE: Gabe <begeddov@proaxis.com> raises this issue regarding
 * <ACE_OS::gethrtime>: on multi-processors, the processor that
 * you query for your <timer.stop> value might not be the one
 * you queried for <timer.start>.  Its not clear how much
 * divergence there would be, if any.
 * This issue is not mentioned in the Solaris 2.5.1 gethrtime
 * man page.
 */
class ACE_Export ACE_High_Res_Timer
{
public:
  // = Initialization method.

  /**
   * global_scale_factor_ is set to <gsf>.  All High_Res_Timers use
   * global_scale_factor_.  This allows applications to set the scale
   * factor just once for all High_Res_Timers.  Check
   * High_Res_Timer.cpp for the default global_scale_factors for
   * several platforms.  For many platforms (e.g., Solaris), the
   * global_scale_factor_ is set to 1000 so that <scale_factor> need
   * not be set.  Careful, a <scale_factor> of 0 will cause division
   * by zero exceptions.
   */
  static void global_scale_factor (ACE_UINT32 gsf);

  /// Returns the global_scale_factor.
  static ACE_UINT32 global_scale_factor (void);

  // On Win32, QueryPerformanceFrequency is used as a base for the global
  // scale factor. The value this returns is often too small to be usefully
  // converted to "ticks"/second - it loses unacceptably high levels of
  // precision. So on Win32, global_scale_factor_ is in ticks/msec, not
  // ticks/usec as on all others.
#if defined (ACE_WIN32)
#  define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_MSECS)
#else
#  define ACE_HR_SCALE_CONVERSION (ACE_ONE_SECOND_IN_USECS)
#endif /* ACE_WIN32 */

  /**
   * Sets the global_scale_factor to the value in the <env>
   * environment variable.  Returns 0 on success, -1 on failure.  Note
   * if <env> points to string "0" (value zero), this call will fail.
   * This is basically a no-op on CE because there is no concept of
   * environment variable on CE.
   */
  static int get_env_global_scale_factor (const ACE_TCHAR *env
                                          = ACE_LIB_TEXT ("ACE_SCALE_FACTOR"));

  /**
   * Set (and return, for info) the global scale factor by sleeping
   * for <usec> and counting the number of intervening clock cycles.
   * Average over <iterations> of <usec> each.  On some platforms,
   * such as Pentiums, this is called automatically during the first
   * ACE_High_Res_Timer construction with the default parameter
   * values.  An application can override that by calling calibrate
   * with any desired parameter values _prior_ to constructing the
   * first ACE_High_Res_Timer instance.
   */
  static ACE_UINT32 calibrate (const ACE_UINT32 usec = 500000,
                               const u_int iterations = 10);

  /// Initialize the timer.
  ACE_High_Res_Timer (void);

  /// dtor.
  ~ACE_High_Res_Timer (void);

  /// Reinitialize the timer.
  void reset (void);

  /// Start timing.
  void start (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);

  /// Stop timing.
  void stop (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);

  /// Set <tv> to the number of microseconds elapsed.
  void elapsed_time (ACE_Time_Value &tv) const;

  /// Set <nanoseconds> to the number of nanoseconds elapsed.
  void elapsed_time (ACE_hrtime_t &nanoseconds) const;

#if defined (ACE_HAS_POSIX_TIME)
  /// Returns the elapsed (stop - start) time in a struct timespec
  /// (sec, nsec).
  void elapsed_time (struct timespec &) const;
#endif /* ACE_HAS_POSIX_TIME */

  /// Sets <usecs> to the elapsed (stop - start) time in microseconds.
  void elapsed_microseconds (ACE_hrtime_t &usecs) const;

  /// Start incremental timing.
  void start_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);

  /// Stop incremental timing.
  void stop_incr (const ACE_OS::ACE_HRTimer_Op = ACE_OS::ACE_HRTIMER_GETTIME);

  /// Set <tv> to the number of microseconds elapsed between all calls
  /// to start_incr and stop_incr.
  void elapsed_time_incr (ACE_Time_Value &tv) const;

  /// Set <nsec> to the number of nanoseconds elapsed between all calls
  /// to start_incr and stop_incr.
  void elapsed_time_incr (ACE_hrtime_t &nanoseconds) const;

#if !defined (ACE_HAS_WINCE)
  // @@ WINCE These two functions are currently not supported on Windows CE.
  //    However, we should probably use the handle and ACE_Log_Msg to
  //    print out the result.
  /// Print total time.  NOTE: only use <print_total> if incremental
  /// timings had been used!
  void print_total (const ACE_TCHAR *message,
                    const int iterations = 1,
                    ACE_HANDLE handle = ACE_STDOUT) const;

  /// Print average time.
  void print_ave (const ACE_TCHAR *message,
                  const int iterations = 1,
                  ACE_HANDLE handle = ACE_STDOUT) const;
#endif /* !ACE_HAS_WINCE */

  /// Dump the state of an object.
  void dump (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;

  /**
   * Get the current "time" as the high resolution counter at this time.
   * This is intended to be useful for supplying to a ACE_Timer_Queue
   * as the gettimeofday function, thereby basing the timer calculations
   * on the high res timer rather than wall clock time.
   */
  static ACE_Time_Value gettimeofday_hr (void);

  /**
   * THIS FUNCTION IS DEPRECATED.  PLEASE USE <ACE_OS::gettimeofday>
   * INSTEAD!  Calls <ACE_High_Res_Timer::hrtime_to_tv> passing
   * <ACE_OS::gethrtime>.  This function can be used to parameterize
   * objects such as <ACE_Timer_Queue::gettimeofday>.  If
   * <global_scale_factor_> is not set, and we're on a platform that
   * requires <global_scale_factor_> (e.g., Win32),
   * ACE_OS::gettimeofday will be used instead of <ACE_OS::gethrtime>.
   * This allows applications on Intel to use <High_Res_Timer> even
   * when <global_scale_factor> is not set.  However, setting the
   * <global_scale_factor_> appropriately will result in the finest
   * resolution possible.
   */
  static ACE_Time_Value gettimeofday (const ACE_OS::ACE_HRTimer_Op =
                                        ACE_OS::ACE_HRTIMER_GETTIME);

  /// Converts an <hrt> to <tv> using global_scale_factor_.
  static void hrtime_to_tv (ACE_Time_Value &tv,
                            const ACE_hrtime_t hrt);

#if defined (linux)
  /**
   * This is used to find out the Mhz of the machine for the scale
   * factor.  If there are any problems getting it, we just return 1
   * (the default).
   */
  static ACE_UINT32 get_cpuinfo (void);
#endif /* defined (linux) */

private:
  /**
   * For internal use: gets the high-resolution time using
   * <ACE_OS::gethrtime>.  Except on platforms that require that the
   * <global_scale_factor_> be set, such as ACE_WIN32, uses the
   * low-resolution clock if the <global_scale_factor_> has not been
   * set.
   */
  static ACE_hrtime_t gettime (const ACE_OS::ACE_HRTimer_Op =
                                 ACE_OS::ACE_HRTIMER_GETTIME);

  /// Starting time.
  ACE_hrtime_t start_;

  /// Ending time.
  ACE_hrtime_t end_;

  /// Total elapsed time.
  ACE_hrtime_t total_;

  /// Start time of incremental timing.
  ACE_hrtime_t start_incr_;

  /// Converts ticks to microseconds.  That is, ticks /
  /// global_scale_factor_ == microseconds.
  static ACE_UINT32 global_scale_factor_;

  /**
   * Indicates the status of the global scale factor,
   * 0  = hasn't been set
   * 1  = been set
   * -1 = HR timer not supported
   */
  static int global_scale_factor_status_;
};

#if defined (__ACE_INLINE__)
#include "ace/High_Res_Timer.i"
#endif /* __ACE_INLINE__ */

#include "ace/post.h"
#endif /* ACE_HIGH_RES_TIMER_H */