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