00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "ace/High_Res_Timer.h"
00011
00012 #if !defined (__ACE_INLINE__)
00013 #include "ace/High_Res_Timer.inl"
00014 #endif
00015
00016 #include "ace/Stats.h"
00017 #include "ace/OS_NS_stdio.h"
00018 #include "ace/OS_NS_string.h"
00019 #include "ace/OS_NS_sys_time.h"
00020 #include "ace/OS_NS_time.h"
00021 #include "ace/OS_NS_unistd.h"
00022 #include "ace/OS_NS_stdlib.h"
00023 #include "ace/Truncate.h"
00024
00025 ACE_RCSID(ace, High_Res_Timer, "$Id: High_Res_Timer.cpp 79134 2007-07-31 18:23:50Z johnnyw $")
00026
00027 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00028
00029 ACE_ALLOC_HOOK_DEFINE(ACE_High_Res_Timer)
00030
00031 ACE_END_VERSIONED_NAMESPACE_DECL
00032
00033
00034
00035
00036 #if (defined (ACE_WIN32) || defined (ACE_HAS_POWERPC_TIMER) || \
00037 defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER)) && \
00038 !defined (ACE_HAS_HI_RES_TIMER)
00039
00040 # include "ace/Guard_T.h"
00041 # include "ace/Recursive_Thread_Mutex.h"
00042 # include "ace/Object_Manager.h"
00043
00044 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00045
00046
00047
00048
00049
00050 ACE_UINT32 ACE_High_Res_Timer::global_scale_factor_ = 1u;
00051
00052 ACE_END_VERSIONED_NAMESPACE_DECL
00053
00054 #else
00055
00056
00057
00058 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00059
00060
00061
00062
00063 ACE_UINT32 ACE_High_Res_Timer::global_scale_factor_ = 1000u;
00064
00065 ACE_END_VERSIONED_NAMESPACE_DECL
00066 #endif
00067
00068
00069
00070 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00071
00072
00073
00074
00075 int ACE_High_Res_Timer::global_scale_factor_status_ = 0;
00076
00077
00078 #if defined (linux)
00079
00080 ACE_UINT32
00081 ACE_High_Res_Timer::get_cpuinfo (void)
00082 {
00083 ACE_UINT32 scale_factor = 1u;
00084
00085
00086
00087
00088
00089
00090 #if !defined (__alpha__)
00091 int supported = 0;
00092 #endif
00093
00094 FILE *cpuinfo = ACE_OS::fopen (ACE_TEXT ("/proc/cpuinfo"),
00095 ACE_TEXT ("r"));
00096
00097 if (cpuinfo != 0)
00098 {
00099 char buf[128];
00100
00101
00102
00103 while (ACE_OS::fgets (buf, sizeof buf, cpuinfo))
00104 {
00105 #if defined (__alpha__)
00106 ACE_UINT32 whole;
00107 ACE_UINT32 fractional;
00108 if (::sscanf (buf,
00109 "BogoMIPS : %d.%d\n",
00110 &whole,
00111 &fractional) == 2
00112 || ::sscanf (buf,
00113 "bogomips : %d.%d\n",
00114 &whole,
00115 &fractional) == 2)
00116 {
00117 scale_factor = whole;
00118 break;
00119 }
00120 #else
00121 double mhertz = 1;
00122 double bmips = 1;
00123 char arg[128];
00124
00125
00126 if (::sscanf (buf, "cpu : %s\n", arg) == 1)
00127 {
00128
00129
00130 if (ACE_OS::strncmp (arg,
00131 "Alpha",
00132 5) == 0)
00133 {
00134 supported = 1;
00135
00136 }
00137 }
00138
00139 else if (supported == 0
00140 && ::sscanf (buf, "model name : Pentium %s\n", arg) == 1)
00141 {
00142
00143
00144 if (ACE_OS::strcmp (arg, "II") == 0
00145 || ACE_OS::strcmp (arg, "III") == 0
00146 || ACE_OS::strcmp (arg, "IV") == 0
00147 || ACE_OS::strcmp (arg, "Pro") == 0)
00148 {
00149 supported = 1;
00150
00151 }
00152 }
00153 else if (::sscanf (buf, "cpu MHz : %lf\n", &mhertz) == 1)
00154 {
00155
00156
00157
00158 scale_factor = (ACE_UINT32) (mhertz + 0.5);
00159 break;
00160 }
00161 else if (::sscanf (buf, "bogomips : %lf\n", &bmips) == 1
00162 || ::sscanf (buf, "BogoMIPS : %lf\n", &bmips) == 1)
00163 {
00164 if (supported)
00165 {
00166 scale_factor = (ACE_UINT32) (bmips + 0.5);
00167
00168 }
00169 #if 0
00170 else
00171 {
00172 ACE_DEBUG ((LM_DEBUG,
00173 ACE_TEXT ("\nThe BogoMIPS metric is not supported on this platform"
00174 "\n\tReport the results of the clock calibration and"
00175 "\n\tthe contents of /proc/cpuinfo to the ace-users mailing list")));
00176 }
00177 #endif
00178 break;
00179 }
00180 #endif
00181 }
00182
00183
00184
00185 ACE_OS::fclose (cpuinfo);
00186 }
00187
00188 return scale_factor;
00189 }
00190 #endif
00191
00192 ACE_UINT32
00193 ACE_High_Res_Timer::global_scale_factor (void)
00194 {
00195 #if (defined (ACE_WIN32) || defined (ACE_HAS_POWERPC_TIMER) || \
00196 defined (ACE_HAS_PENTIUM) || defined (ACE_HAS_ALPHA_TIMER)) && \
00197 !defined (ACE_HAS_HI_RES_TIMER) && \
00198 ((defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) || \
00199 defined (ghs) || defined (__GNUG__) || \
00200 defined (__INTEL_COMPILER))
00201
00202 if (ACE_High_Res_Timer::global_scale_factor_status_ == 0)
00203 {
00204
00205
00206 ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon,
00207 *ACE_Static_Object_Lock::instance (), 0));
00208
00209
00210 if (ACE_High_Res_Timer::global_scale_factor_status_ == 0)
00211 {
00212 # if defined (ACE_WIN32)
00213 LARGE_INTEGER freq;
00214 if (::QueryPerformanceFrequency (&freq))
00215 {
00216
00217 # if defined (ACE_LACKS_LONGLONG_T)
00218 ACE_UINT64 uint64_freq(freq.u.LowPart, (ACE_UINT32) freq.u.HighPart);
00219 ACE_High_Res_Timer::global_scale_factor
00220 (uint64_freq / (ACE_UINT32) ACE_ONE_SECOND_IN_USECS);
00221 # else
00222 ACE_High_Res_Timer::global_scale_factor
00223 (static_cast<unsigned int> (freq.QuadPart / ACE_HR_SCALE_CONVERSION));
00224 # endif // (ACE_LACKS_LONGLONG_T)
00225
00226 ACE_High_Res_Timer::global_scale_factor_status_ = 1;
00227 }
00228 else
00229
00230 ACE_High_Res_Timer::global_scale_factor_status_ = -1;
00231
00232 return ACE_High_Res_Timer::global_scale_factor_;
00233
00234 # elif defined (linux)
00235 ACE_High_Res_Timer::global_scale_factor (ACE_High_Res_Timer::get_cpuinfo ());
00236 # endif
00237
00238 # if !defined (ACE_WIN32)
00239 if (ACE_High_Res_Timer::global_scale_factor_ == 1u)
00240
00241 ACE_High_Res_Timer::calibrate ();
00242 # endif // (ACE_WIN32)
00243 }
00244 }
00245
00246 ACE_High_Res_Timer::global_scale_factor_status_ = 1;
00247 #endif
00248
00249
00250
00251
00252 return ACE_High_Res_Timer::global_scale_factor_;
00253 }
00254
00255 ACE_High_Res_Timer::ACE_High_Res_Timer (void)
00256 {
00257 ACE_TRACE ("ACE_High_Res_Timer::ACE_High_Res_Timer");
00258
00259 this->reset ();
00260
00261
00262 (void) global_scale_factor ();
00263 }
00264
00265 ACE_UINT32
00266 ACE_High_Res_Timer::calibrate (const ACE_UINT32 usec,
00267 const u_int iterations)
00268 {
00269 const ACE_Time_Value sleep_time (0, usec);
00270 ACE_Stats delta_hrtime;
00271
00272 ACE_Stats actual_sleeps;
00273
00274 for (u_int i = 0;
00275 i < iterations;
00276 ++i)
00277 {
00278 const ACE_Time_Value actual_start =
00279 ACE_OS::gettimeofday ();
00280 const ACE_hrtime_t start =
00281 ACE_OS::gethrtime ();
00282 ACE_OS::sleep (sleep_time);
00283 const ACE_hrtime_t stop =
00284 ACE_OS::gethrtime ();
00285 const ACE_Time_Value actual_delta =
00286 ACE_OS::gettimeofday () - actual_start;
00287
00288
00289 delta_hrtime.sample (ACE_Utils::truncate_cast<ACE_INT32> (stop - start));
00290 actual_sleeps.sample (actual_delta.msec () * 100u);
00291 }
00292
00293
00294
00295 ACE_Stats_Value ticks (0);
00296 delta_hrtime.mean (ticks);
00297
00298 ACE_Stats_Value actual_sleep (0);
00299 actual_sleeps.mean (actual_sleep);
00300
00301
00302 const ACE_UINT32 scale_factor =
00303 (ticks.whole () / actual_sleep.whole () + 5) /
00304 10u ;
00305 ACE_High_Res_Timer::global_scale_factor (scale_factor);
00306
00307 return scale_factor;
00308 }
00309
00310 void
00311 ACE_High_Res_Timer::dump (void) const
00312 {
00313 #if defined (ACE_HAS_DUMP)
00314 ACE_TRACE ("ACE_High_Res_Timer::dump");
00315
00316 ACE_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this));
00317 ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("\nglobal_scale_factor_: %u\n"),
00318 global_scale_factor ()));
00319 #if defined (ACE_LACKS_LONGLONG_T)
00320 ACE_DEBUG ((LM_DEBUG,
00321 ACE_TEXT (":\nstart_.hi (): %8x; start_.lo (): %8x;\n")
00322 ACE_TEXT ("end_.hi (): %8x; end_.lo (): %8x;\n")
00323 ACE_TEXT ("total_.hi (): %8x; total_.lo (): %8x;\n")
00324 ACE_TEXT ("start_incr_.hi () %8x; start_incr_.lo (): %8x;\n"),
00325 start_.hi (), start_.lo (),
00326 end_.hi (), end_.lo (),
00327 total_.hi (), total_.lo (),
00328 start_incr_.hi (), start_incr_.lo ()));
00329 #else
00330 ACE_DEBUG ((LM_DEBUG,
00331 ACE_TEXT (":\nstart_.hi (): %8x; start_.lo (): %8x;\n")
00332 ACE_TEXT ("end_.hi (): %8x; end_.lo (): %8x;\n")
00333 ACE_TEXT ("total_.hi (): %8x; total_.lo (): %8x;\n")
00334 ACE_TEXT ("start_incr_.hi () %8x; start_incr_.lo (): %8x;\n"),
00335 static_cast<ACE_UINT32> (start_ >> 32),
00336 static_cast<ACE_UINT32> (start_ & 0xfffffffful),
00337 static_cast<ACE_UINT32> (end_ >> 32),
00338 static_cast<ACE_UINT32> (end_ & 0xfffffffful),
00339 static_cast<ACE_UINT32> (total_ >> 32),
00340 static_cast<ACE_UINT32> (total_ & 0xfffffffful),
00341 static_cast<ACE_UINT32> (start_incr_ >> 32),
00342 static_cast<ACE_UINT32> (start_incr_ & 0xfffffffful)));
00343 #endif
00344 ACE_DEBUG ((LM_DEBUG, ACE_END_DUMP));
00345 #endif
00346 }
00347
00348 void
00349 ACE_High_Res_Timer::reset (void)
00350 {
00351 ACE_TRACE ("ACE_High_Res_Timer::reset");
00352
00353 this->start_ = 0;
00354 this->end_ = 0;
00355 this->total_ = 0;
00356 this->start_incr_ = 0;
00357 }
00358
00359 void
00360 ACE_High_Res_Timer::elapsed_time (ACE_Time_Value &tv) const
00361 {
00362 hrtime_to_tv (tv,
00363 ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_));
00364 }
00365
00366 #if defined (ACE_HAS_POSIX_TIME)
00367
00368
00369
00370 void
00371 ACE_High_Res_Timer::elapsed_time (struct timespec &elapsed_time) const
00372 {
00373
00374
00375
00376
00377
00378
00379
00380
00381 ACE_hrtime_t elapsed =
00382 ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_);
00383 u_long nseconds = static_cast<u_long> (elapsed %
00384 global_scale_factor () * 1000u /
00385 global_scale_factor ());
00386
00387
00388 ACE_UINT32 useconds = (ACE_UINT32) (elapsed / global_scale_factor ());
00389
00390 elapsed_time.tv_sec = (time_t) (useconds / ACE_ONE_SECOND_IN_USECS);
00391
00392 elapsed_time.tv_nsec = (time_t) ((useconds % ACE_ONE_SECOND_IN_USECS) * 1000u + nseconds);
00393 }
00394 #endif
00395
00396 void
00397 ACE_High_Res_Timer::elapsed_time_incr (ACE_Time_Value &tv) const
00398 {
00399 hrtime_to_tv (tv, total_);
00400 }
00401
00402 void
00403 ACE_High_Res_Timer::elapsed_time (ACE_hrtime_t &nanoseconds) const
00404 {
00405
00406
00407
00408
00409 nanoseconds = ACE_High_Res_Timer::elapsed_hrtime (this->end_, this->start_)
00410 * (1024000u / ACE_High_Res_Timer::global_scale_factor ());
00411
00412 nanoseconds = nanoseconds >> 10;
00413
00414
00415 }
00416
00417 void
00418 ACE_High_Res_Timer::elapsed_time_incr (ACE_hrtime_t &nanoseconds) const
00419 {
00420
00421 nanoseconds = this->total_
00422 * (1024000u / ACE_High_Res_Timer::global_scale_factor ());
00423
00424 nanoseconds = nanoseconds >> 10;
00425 }
00426
00427 #if !defined (ACE_HAS_WINCE)
00428 void
00429 ACE_High_Res_Timer::print_ave (const ACE_TCHAR *str,
00430 const int count,
00431 ACE_HANDLE handle) const
00432 {
00433 ACE_TRACE ("ACE_High_Res_Timer::print_ave");
00434
00435
00436 ACE_hrtime_t total_nanoseconds;
00437 this->elapsed_time (total_nanoseconds);
00438
00439
00440 u_long total_secs =
00441 static_cast<u_long> (total_nanoseconds / (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
00442 ACE_UINT32 extra_nsecs =
00443 static_cast<ACE_UINT32> (total_nanoseconds % (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
00444
00445 ACE_TCHAR buf[100];
00446 if (count > 1)
00447 {
00448 ACE_hrtime_t avg_nsecs = total_nanoseconds / (ACE_UINT32) count;
00449 ACE_OS::sprintf (buf,
00450 ACE_TEXT (" count = %d, total (secs %lu, usecs %u), avg usecs = %lu\n"),
00451 count,
00452 total_secs,
00453 (extra_nsecs + 500u) / 1000u,
00454 (u_long) ((avg_nsecs + 500u) / 1000u));
00455 }
00456 else
00457 ACE_OS::sprintf (buf,
00458 ACE_TEXT (" total %3lu.%06lu secs\n"),
00459 total_secs,
00460 (extra_nsecs + 500lu) / 1000lu);
00461
00462 ACE_OS::write (handle,
00463 str,
00464 ACE_OS::strlen (str));
00465 ACE_OS::write (handle,
00466 buf,
00467 ACE_OS::strlen (buf));
00468 }
00469
00470 void
00471 ACE_High_Res_Timer::print_total (const ACE_TCHAR *str,
00472 const int count,
00473 ACE_HANDLE handle) const
00474 {
00475 ACE_TRACE ("ACE_High_Res_Timer::print_total");
00476
00477
00478 ACE_hrtime_t total_nanoseconds;
00479 this->elapsed_time (total_nanoseconds);
00480
00481
00482 u_long total_secs =
00483 (u_long) (total_nanoseconds / (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
00484 ACE_UINT32 extra_nsecs =
00485 (ACE_UINT32) (total_nanoseconds % (ACE_UINT32) ACE_ONE_SECOND_IN_NSECS);
00486
00487 ACE_TCHAR buf[100];
00488 if (count > 1)
00489 {
00490 ACE_hrtime_t avg_nsecs = this->total_ / (ACE_UINT32) count;
00491
00492 ACE_OS::sprintf (buf,
00493 ACE_TEXT (" count = %d, total (secs %lu, usecs %u), avg usecs = %lu\n"),
00494 count,
00495 total_secs,
00496 (extra_nsecs + 500u) / 1000u,
00497 (u_long) ((avg_nsecs + 500u) / 1000u));
00498 }
00499 else
00500 ACE_OS::sprintf (buf,
00501 ACE_TEXT (" total %3lu.%06u secs\n"),
00502 total_secs,
00503 (extra_nsecs + 500u) / 1000u);
00504
00505 ACE_OS::write (handle,
00506 str,
00507 ACE_OS::strlen (str));
00508 ACE_OS::write (handle,
00509 buf,
00510 ACE_OS::strlen (buf));
00511 }
00512 #endif
00513
00514 int
00515 ACE_High_Res_Timer::get_env_global_scale_factor (const ACE_TCHAR *env)
00516 {
00517 #if !defined (ACE_HAS_WINCE)
00518 if (env != 0)
00519 {
00520 const char *env_value = ACE_OS::getenv (ACE_TEXT_ALWAYS_CHAR (env));
00521 if (env_value != 0)
00522 {
00523 int const value = ACE_OS::atoi (env_value);
00524 if (value > 0)
00525 {
00526 ACE_High_Res_Timer::global_scale_factor (value);
00527 return 0;
00528 }
00529 }
00530 }
00531 #else
00532 ACE_UNUSED_ARG (env);
00533 #endif
00534 return -1;
00535 }
00536
00537 ACE_END_VERSIONED_NAMESPACE_DECL