Stats.cpp

Go to the documentation of this file.
00001 // Stats.cpp,v 4.36 2005/10/28 16:14:56 ossama Exp
00002 
00003 #include "ace/Stats.h"
00004 
00005 #if !defined (__ACE_INLINE__)
00006 # include "ace/Stats.inl"
00007 #endif /* __ACE_INLINE__ */
00008 
00009 #include "ace/High_Res_Timer.h"
00010 #include "ace/OS_NS_stdio.h"
00011 #include "ace/OS_NS_string.h"
00012 
00013 ACE_RCSID(ace, Stats, "Stats.cpp,v 4.36 2005/10/28 16:14:56 ossama Exp")
00014 
00015 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00016 
00017 ACE_UINT32
00018 ACE_Stats_Value::fractional_field (void) const
00019 {
00020   if (precision () == 0)
00021     {
00022       return 1;
00023     }
00024   else
00025     {
00026       ACE_UINT32 field = 10;
00027       for (u_int i = 0; i < precision () - 1; ++i)
00028         {
00029           field *= 10;
00030         }
00031 
00032       return field;
00033     }
00034 }
00035 
00036 int
00037 ACE_Stats::sample (const ACE_INT32 value)
00038 {
00039   if (samples_.enqueue_tail (value) == 0)
00040     {
00041       ++number_of_samples_;
00042       if (number_of_samples_ == 0)
00043         {
00044           // That's a lot of samples :-)
00045           overflow_ = EFAULT;
00046           return -1;
00047         }
00048 
00049       if (value < min_)
00050         min_ = value;
00051 
00052       if (value > max_)
00053         max_ = value;
00054 
00055       return 0;
00056     }
00057   else
00058     {
00059       // Probably failed due to running out of memory when trying to
00060       // enqueue the new value.
00061       overflow_ = errno;
00062       return -1;
00063     }
00064 }
00065 
00066 void
00067 ACE_Stats::mean (ACE_Stats_Value &m,
00068                  const ACE_UINT32 scale_factor)
00069 {
00070   if (number_of_samples_ > 0)
00071     {
00072 #if defined ACE_LACKS_LONGLONG_T
00073       // If ACE_LACKS_LONGLONG_T, then ACE_UINT64 is a user-defined class.
00074       // To prevent having to construct a static of that class, declare it
00075       // on the stack, and construct it, in each function that needs it.
00076       const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8);
00077 #else  /* ! ACE_LACKS_LONGLONG_T */
00078       const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET =
00079         ACE_UINT64_LITERAL (0x100000000);
00080 #endif /* ! ACE_LACKS_LONGLONG_T */
00081 
00082       ACE_UINT64 sum = ACE_STATS_INTERNAL_OFFSET;
00083       ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
00084       while (! i.done ())
00085         {
00086           ACE_INT32 *sample;
00087           if (i.next (sample))
00088             {
00089               sum += *sample;
00090               i.advance ();
00091             }
00092         }
00093 
00094       // sum_ was initialized with ACE_STATS_INTERNAL_OFFSET, so
00095       // subtract that off here.
00096       quotient (sum - ACE_STATS_INTERNAL_OFFSET,
00097                 number_of_samples_ * scale_factor,
00098                 m);
00099     }
00100   else
00101     {
00102       m.whole (0);
00103       m.fractional (0);
00104     }
00105 }
00106 
00107 int
00108 ACE_Stats::std_dev (ACE_Stats_Value &std_dev,
00109                     const ACE_UINT32 scale_factor)
00110 {
00111   if (number_of_samples_ <= 1)
00112     {
00113       std_dev.whole (0);
00114       std_dev.fractional (0);
00115     }
00116   else
00117     {
00118       const ACE_UINT32 field = std_dev.fractional_field ();
00119 
00120       // The sample standard deviation is:
00121       //
00122       // sqrt (sum (sample_i - mean)^2 / (number_of_samples_ - 1))
00123 
00124       ACE_UINT64 mean_scaled;
00125       // Calculate the mean, scaled, so that we don't lose its
00126       // precision.
00127       ACE_Stats_Value avg (std_dev.precision ());
00128       mean (avg, 1u);
00129       avg.scaled_value (mean_scaled);
00130 
00131       // Calculate the summation term, of squared differences from the
00132       // mean.
00133       ACE_UINT64 sum_of_squares = 0;
00134       ACE_Unbounded_Queue_Iterator<ACE_INT32> i (samples_);
00135       while (! i.done ())
00136         {
00137           ACE_INT32 *sample;
00138           if (i.next (sample))
00139             {
00140               const ACE_UINT64 original_sum_of_squares = sum_of_squares;
00141 
00142               // Scale up by field width so that we don't lose the
00143               // precision of the mean.  Carefully . . .
00144               const ACE_UINT64 product (*sample * field);
00145 
00146               ACE_UINT64 difference;
00147               // NOTE: please do not reformat this code!  It //
00148               // works with the Diab compiler the way it is! //
00149               if  (product >= mean_scaled)                   //
00150                 {                                            //
00151                   difference = product - mean_scaled;        //
00152                 }                                            //
00153               else                                           //
00154                 {                                            //
00155                   difference = mean_scaled - product;        //
00156                 }                                            //
00157               // NOTE: please do not reformat this code!  It //
00158               // works with the Diab compiler the way it is! //
00159 
00160               // Square using 64-bit arithmetic.
00161               sum_of_squares += difference * ACE_U64_TO_U32 (difference);
00162               i.advance ();
00163 
00164               if (sum_of_squares < original_sum_of_squares)
00165                 {
00166                   overflow_ = ENOSPC;
00167                   return -1;
00168                 }
00169             }
00170         }
00171 
00172       // Divide the summation by (number_of_samples_ - 1), to get the
00173       // variance.  In addition, scale the variance down to undo the
00174       // mean scaling above.  Otherwise, it can get too big.
00175       ACE_Stats_Value variance (std_dev.precision ());
00176       quotient (sum_of_squares,
00177                 (number_of_samples_ - 1) * field * field,
00178                 variance);
00179 
00180       // Take the square root of the variance to get the standard
00181       // deviation.  First, scale up . . .
00182       ACE_UINT64 scaled_variance;
00183       variance.scaled_value (scaled_variance);
00184 
00185       // And scale up, once more, because we'll be taking the square
00186       // root.
00187       scaled_variance *= field;
00188       ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ());
00189       square_root (scaled_variance,
00190                    unscaled_standard_deviation);
00191 
00192       // Unscale.
00193       quotient (unscaled_standard_deviation,
00194                 scale_factor * field,
00195                 std_dev);
00196     }
00197 
00198   return 0;
00199 }
00200 
00201 
00202 void
00203 ACE_Stats::reset (void)
00204 {
00205   overflow_ = 0u;
00206   number_of_samples_ = 0u;
00207   min_ = 0x7FFFFFFF;
00208   max_ = -0x8000 * 0x10000;
00209   samples_.reset ();
00210 }
00211 
00212 int
00213 ACE_Stats::print_summary (const u_int precision,
00214                           const ACE_UINT32 scale_factor,
00215                           FILE *file) const
00216 {
00217   ACE_TCHAR mean_string [128];
00218   ACE_TCHAR std_dev_string [128];
00219   ACE_TCHAR min_string [128];
00220   ACE_TCHAR max_string [128];
00221   int success = 0;
00222 
00223   for (int tmp_precision = precision;
00224        ! overflow_  &&  ! success  &&  tmp_precision >= 0;
00225        --tmp_precision)
00226     {
00227       // Build a format string, in case the C library doesn't support %*u.
00228       ACE_TCHAR format[32];
00229       if (tmp_precision == 0)
00230         ACE_OS::sprintf (format, ACE_LIB_TEXT ("%%%d"), tmp_precision);
00231       else
00232         ACE_OS::sprintf (format, ACE_LIB_TEXT ("%%d.%%0%du"), tmp_precision);
00233 
00234       ACE_Stats_Value u (tmp_precision);
00235       ((ACE_Stats *) this)->mean (u, scale_factor);
00236       ACE_OS::sprintf (mean_string, format, u.whole (), u.fractional ());
00237 
00238       ACE_Stats_Value sd (tmp_precision);
00239       if (((ACE_Stats *) this)->std_dev (sd, scale_factor))
00240         {
00241           success = 0;
00242           continue;
00243         }
00244       else
00245         {
00246           success = 1;
00247         }
00248       ACE_OS::sprintf (std_dev_string, format, sd.whole (), sd.fractional ());
00249 
00250       ACE_Stats_Value minimum (tmp_precision), maximum (tmp_precision);
00251       if (min_ != 0)
00252         {
00253           const ACE_UINT64 m (min_);
00254           quotient (m, scale_factor, minimum);
00255         }
00256       if (max_ != 0)
00257         {
00258           const ACE_UINT64 m (max_);
00259           quotient (m, scale_factor, maximum);
00260         }
00261       ACE_OS::sprintf (min_string, format,
00262                        minimum.whole (), minimum.fractional ());
00263       ACE_OS::sprintf (max_string, format,
00264                        maximum.whole (), maximum.fractional ());
00265     }
00266 
00267   if (success == 1)
00268     {
00269       ACE_OS::fprintf (file, ACE_LIB_TEXT ("samples: %u (%s - %s); mean: ")
00270                        ACE_LIB_TEXT ("%s; std dev: %s\n"),
00271                        samples (), min_string, max_string,
00272                        mean_string, std_dev_string);
00273       return 0;
00274     }
00275   else
00276     {
00277 #if !defined (ACE_HAS_WINCE)
00278       ACE_OS::fprintf (file,
00279                        ACE_LIB_TEXT ("ACE_Stats::print_summary: OVERFLOW: %s\n"),
00280                        ACE_OS::strerror (overflow_));
00281 #else
00282       // WinCE doesn't have strerror ;(
00283       ACE_OS::fprintf (file,
00284                        ACE_LIB_TEXT ("ACE_Stats::print_summary: OVERFLOW\n"));
00285 #endif /* ACE_HAS_WINCE */
00286       return -1;
00287     }
00288 }
00289 
00290 void
00291 ACE_Stats::quotient (const ACE_UINT64 dividend,
00292                      const ACE_UINT32 divisor,
00293                      ACE_Stats_Value &quotient)
00294 {
00295   // The whole part of the division comes from simple integer division.
00296   quotient.whole (static_cast<ACE_UINT32> (divisor == 0
00297                                            ?  0  :  dividend / divisor));
00298 
00299   if (quotient.precision () > 0  ||  divisor == 0)
00300     {
00301       const ACE_UINT32 field = quotient.fractional_field ();
00302 
00303       // Fractional = (dividend % divisor) * 10^precision / divisor
00304 
00305       // It would be nice to add round-up term:
00306       // Fractional = (dividend % divisor) * 10^precision / divisor  +
00307       //                10^precision/2 / 10^precision
00308       //            = ((dividend % divisor) * 10^precision  +  divisor) /
00309       //                divisor
00310       quotient.fractional (static_cast<ACE_UINT32> (
00311                              dividend % divisor * field / divisor));
00312     }
00313   else
00314     {
00315       // No fractional portion is requested, so don't bother
00316       // calculating it.
00317       quotient.fractional (0);
00318     }
00319 }
00320 
00321 void
00322 ACE_Stats::quotient (const ACE_Stats_Value &dividend,
00323                      const ACE_UINT32 divisor,
00324                      ACE_Stats_Value &quotient)
00325 {
00326   // The whole part of the division comes from simple integer division.
00327   quotient.whole (divisor == 0  ?  0  :  dividend.whole () / divisor);
00328 
00329   if (quotient.precision () > 0  ||  divisor == 0)
00330     {
00331       const ACE_UINT32 field = quotient.fractional_field ();
00332 
00333       // Fractional = (dividend % divisor) * 10^precision / divisor.
00334       quotient.fractional (dividend.whole () % divisor * field / divisor  +
00335                            dividend.fractional () / divisor);
00336     }
00337   else
00338     {
00339       // No fractional portion is requested, so don't bother
00340       // calculating it.
00341       quotient.fractional (0);
00342     }
00343 }
00344 
00345 void
00346 ACE_Stats::square_root (const ACE_UINT64 n,
00347                         ACE_Stats_Value &square_root)
00348 {
00349   ACE_UINT32 floor = 0;
00350   ACE_UINT32 ceiling = 0xFFFFFFFFu;
00351   ACE_UINT32 mid = 0;
00352   u_int i;
00353 
00354   // The maximum number of iterations is log_2 (2^64) == 64.
00355   for (i = 0; i < 64; ++i)
00356     {
00357       mid = (ceiling - floor) / 2  +  floor;
00358       if (floor == mid)
00359         // Can't divide the interval any further.
00360         break;
00361       else
00362         {
00363           // Multiply carefully to avoid overflow.
00364           ACE_UINT64 mid_squared = mid; mid_squared *= mid;
00365           if (mid_squared == n)
00366             break;
00367           else if (mid_squared < n)
00368             floor = mid;
00369           else
00370             ceiling = mid;
00371         }
00372     }
00373 
00374   square_root.whole (mid);
00375   ACE_UINT64 mid_squared = mid; mid_squared *= mid;
00376 
00377   if (square_root.precision ()  &&  mid_squared < n)
00378     {
00379       // (mid * 10^precision + fractional)^2 ==
00380       //   n^2 * 10^(precision * 2)
00381 
00382       const ACE_UINT32 field = square_root.fractional_field ();
00383 
00384       floor = 0;
00385       ceiling = field;
00386       mid = 0;
00387 
00388       // Do the 64-bit arithmetic carefully to avoid overflow.
00389       ACE_UINT64 target = n;
00390       target *= field;
00391       target *= field;
00392 
00393       ACE_UINT64 difference = 0;
00394 
00395       for (i = 0; i < square_root.precision (); ++i)
00396         {
00397           mid = (ceiling - floor) / 2 + floor;
00398 
00399           ACE_UINT64 current = square_root.whole () * field  +  mid;
00400           current *= square_root.whole () * field  +  mid;
00401 
00402           if (floor == mid)
00403             {
00404               difference = target - current;
00405               break;
00406             }
00407           else if (current <= target)
00408             floor = mid;
00409           else
00410             ceiling = mid;
00411         }
00412 
00413       // Check to see if the fractional part should be one greater.
00414       ACE_UINT64 next = square_root.whole () * field  +  mid + 1;
00415       next *= square_root.whole () * field  +  mid + 1;
00416 
00417       square_root.fractional (next - target < difference  ?  mid + 1  :  mid);
00418     }
00419   else
00420     {
00421       // No fractional portion is requested, so don't bother
00422       // calculating it.
00423       square_root.fractional (0);
00424     }
00425 }
00426 
00427 // ****************************************************************
00428 
00429 ACE_Throughput_Stats::ACE_Throughput_Stats (void)
00430   : ACE_Basic_Stats ()
00431   , throughput_last_ (0)
00432 #if 0
00433   // @@TODO: This is what I really wanted to compute, but it just
00434   // does not work.
00435   , throughput_sum_x_ (0)
00436   , throughput_sum_x2_ (0)
00437   , throughput_sum_y_ (0)
00438   , throughput_sum_y2_ (0)
00439   , throughput_sum_xy_ (0)
00440 #endif /* 0 */
00441 {
00442 }
00443 
00444 void
00445 ACE_Throughput_Stats::sample (ACE_UINT64 throughput,
00446                               ACE_UINT64 latency)
00447 {
00448   this->ACE_Basic_Stats::sample (latency);
00449 
00450   if (this->samples_count () == 1u)
00451     {
00452 
00453       this->throughput_last_   = throughput;
00454 #if 0
00455       // @@TODO: This is what I really wanted to compute, but it just
00456       // does not work.
00457       this->throughput_sum_y_  = this->samples_count_;
00458       this->throughput_sum_y2_ = this->samples_count_ * this->samples_count_;
00459       this->throughput_sum_x_  = throughput;
00460       this->throughput_sum_x2_ = throughput * throughput;
00461       this->throughput_sum_xy_ = throughput * this->samples_count_;
00462 
00463       printf ("%f %qu\n", throughput / 400000000.0, this->samples_count_);
00464 #endif /* 0 */
00465     }
00466   else
00467     {
00468       this->throughput_last_ = throughput;
00469 
00470 #if 0
00471       // @@TODO: This is what I really wanted to compute, but it just
00472       // does not work.
00473       this->throughput_sum_y_  += this->samples_count_;
00474       this->throughput_sum_y2_ += this->samples_count_ * this->samples_count_;
00475       this->throughput_sum_x_  += throughput;
00476       this->throughput_sum_x2_ += throughput * throughput;
00477       this->throughput_sum_xy_ += throughput * this->samples_count_;
00478 
00479       printf ("%f %qu\n", throughput / 400000000.0, this->samples_count_);
00480 #endif /* 0 */
00481     }
00482 }
00483 
00484 void
00485 ACE_Throughput_Stats::accumulate (const ACE_Throughput_Stats &rhs)
00486 {
00487   if (rhs.samples_count () == 0u)
00488     return;
00489 
00490   this->ACE_Basic_Stats::accumulate (rhs);
00491 
00492   if (this->samples_count () == 0u)
00493     {
00494       this->throughput_last_   = rhs.throughput_last_;
00495 #if 0
00496       // @@TODO: This is what I really wanted to compute, but it just
00497       // does not work.
00498       this->throughput_sum_x_  = rhs.throughput_sum_x_;
00499       this->throughput_sum_x2_ = rhs.throughput_sum_x2_;
00500       this->throughput_sum_y_  = rhs.throughput_sum_y_;
00501       this->throughput_sum_y2_ = rhs.throughput_sum_y2_;
00502       this->throughput_sum_xy_ = rhs.throughput_sum_xy_;
00503 #endif /* 0 */
00504 
00505       return;
00506     }
00507 
00508 
00509   if (this->throughput_last_ < rhs.throughput_last_)
00510     this->throughput_last_ = rhs.throughput_last_;
00511 
00512 #if 0
00513   // @@TODO: This is what I really wanted to compute, but it just
00514   // does not work.
00515   this->throughput_sum_x_  += rhs.throughput_sum_x_;
00516   this->throughput_sum_x2_ += rhs.throughput_sum_x2_;
00517   this->throughput_sum_y_  += rhs.throughput_sum_y_;
00518   this->throughput_sum_y2_ += rhs.throughput_sum_y2_;
00519   this->throughput_sum_xy_ += rhs.throughput_sum_xy_;
00520 #endif /* 0 */
00521 }
00522 
00523 void
00524 ACE_Throughput_Stats::dump_results (const ACE_TCHAR* msg,
00525                                     ACE_UINT32 sf)
00526 {
00527   if (this->samples_count () == 0u)
00528     {
00529       ACE_DEBUG ((LM_DEBUG,
00530                   ACE_LIB_TEXT ("%s : no data collected\n"), msg));
00531       return;
00532     }
00533 
00534   this->ACE_Basic_Stats::dump_results (msg, sf);
00535 
00536   ACE_Throughput_Stats::dump_throughput (msg, sf,
00537                                          this->throughput_last_,
00538                                          this->samples_count ());
00539 
00540 #if 0
00541   // @@TODO: This is what I really wanted to generate, but it just
00542   // doesn't work.
00543   double t_sum_x =
00544     ACE_CU64_TO_CU32 (this->throughput_sum_x_);// / sf);
00545   //t_sum_x /= 1000000.0;
00546   double t_sum_y =
00547     ACE_CU64_TO_CU32 (this->throughput_sum_y_);
00548   double t_sum_x2 =
00549     ACE_CU64_TO_CU32 (this->throughput_sum_x2_);// / (sf*sf));
00550   //t_sum_x2 /= 1000000.0;
00551   //t_sum_x2 /= 1000000.0;
00552   double t_sum_y2 =
00553     ACE_CU64_TO_CU32 (this->throughput_sum_y2_);
00554   double t_sum_xy =
00555     ACE_CU64_TO_CU32 (this->throughput_sum_xy_);// / sf);
00556   //t_sum_xy /= 1000000.0;
00557   double t_avgx = t_sum_x / this->samples_count ();
00558   double t_avgy = t_sum_y / this->samples_count ();
00559 
00560   double t_a =
00561     (this->samples_count () * t_sum_xy - t_sum_x * t_sum_y)
00562     / (this->samples_count () * t_sum_x2 - t_sum_x * t_sum_x);
00563   double t_b = (t_avgy - t_a * t_avgx);
00564 
00565   t_a *= 1000000.0;
00566 
00567   double d_r =
00568     (t_sum_xy - t_avgx * t_sum_y - t_avgy * t_sum_x
00569      + this->samples_count () * t_avgx * t_avgy);
00570   double n_r =
00571     (t_sum_x2
00572      - this->samples_count () * t_avgx * t_avgx)
00573     * (t_sum_y2
00574        - this->samples_count () * t_avgy * t_avgy);
00575   double t_r = d_r * d_r / n_r;
00576 
00577   //  ACE_DEBUG ((LM_DEBUG,
00578   //              "%s throughput: %.2f/%.2f/%.2f/%.6f/%.2f (avg/a/b/r/elapsed)\n",
00579   //              msg, t_avg, t_a, t_b, t_r, seconds));
00580   //  ACE_DEBUG ((LM_DEBUG,
00581   //              "%s        data: %.2f/%.2f/%.2f/%.6f/%.2f (x/x2/y/y2/xy)\n",
00582   //              msg, t_sum_x, t_sum_x2, t_sum_y, t_sum_y2, t_sum_xy));
00583 #endif
00584 }
00585 
00586 void
00587 ACE_Throughput_Stats::dump_throughput (const ACE_TCHAR *msg,
00588                                        ACE_UINT32 sf,
00589                                        ACE_UINT64 elapsed_time,
00590                                        ACE_UINT32 samples_count)
00591 {
00592 #ifndef ACE_NLOGGING
00593   double seconds =
00594 # if defined ACE_LACKS_LONGLONG_T
00595     elapsed_time / sf;
00596 #elif  defined (ACE_LACKS_UNSIGNEDLONGLONG_T)
00597     static_cast<double> (ACE_UINT64_DBLCAST_ADAPTER (
00598                            ACE_U_LongLong(elapsed_time / sf)));
00599 # else  /* ! ACE_LACKS_LONGLONG_T */
00600     static_cast<double> (ACE_UINT64_DBLCAST_ADAPTER (elapsed_time / sf));
00601 # endif /* ! ACE_LACKS_LONGLONG_T */
00602   seconds /= ACE_HR_SCALE_CONVERSION;
00603 
00604   const double t_avg = samples_count / seconds;
00605 
00606   ACE_DEBUG ((LM_DEBUG,
00607               ACE_LIB_TEXT ("%s throughput: %.2f (events/second)\n"),
00608               msg, t_avg));
00609 #else
00610   ACE_UNUSED_ARG (msg);
00611   ACE_UNUSED_ARG (sf);
00612   ACE_UNUSED_ARG (elapsed_time);
00613   ACE_UNUSED_ARG (samples_count);
00614 #endif /* ACE_NLOGGING */
00615 }
00616 
00617 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:42:05 2006 for ACE by doxygen 1.3.6