Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Stats.cpp

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

Generated on Mon Jun 16 11:21:24 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002