summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-05-20 20:50:30 +0000
committerlevine <levine@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>1998-05-20 20:50:30 +0000
commitd016dbb25181e489ddf458bfa5870bb783b959fa (patch)
tree1620d9d701459cfb7db2c094c5390327b2fc5071
parent2da649db7b790388a99231238ea6f5ba080bb99a (diff)
downloadATCD-d016dbb25181e489ddf458bfa5870bb783b959fa.tar.gz
added ACE_Stats class
-rw-r--r--ace/Stats.cpp337
-rw-r--r--ace/Stats.h172
-rw-r--r--ace/Stats.i79
3 files changed, 588 insertions, 0 deletions
diff --git a/ace/Stats.cpp b/ace/Stats.cpp
new file mode 100644
index 00000000000..b23c917d81c
--- /dev/null
+++ b/ace/Stats.cpp
@@ -0,0 +1,337 @@
+// $Id$
+
+#include "ace/Stats.h"
+
+#if !defined (__ACE_INLINE__)
+# include "ace/Stats.i"
+#endif /* __ACE_INLINE__ */
+
+#if !defined ACE_LACKS_LONGLONG_T
+// 1) If ACE_LACKS_LONGLONG_T, then ACE_UINT64 is a user-defined class.
+// To prevent having to construct a static of that class, declare it
+// on the stack, and construct it in, each function that needs it.
+// 2) To avoid warnings from some compilers, split the 0x100000000ull
+// constant into two pieces.
+static const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET = 0x10000ull * 0x10000ull;
+#endif /* ! ACE_LACKS_LONGLONG_T */
+
+ACE_UINT32
+ACE_Stats_Value::fractional_field (void) const
+{
+ ACE_UINT32 field = 10;
+ for (u_int i = 0; i < precision () - 1; ++i)
+ field *= 10;
+
+ return field;
+}
+
+int
+ACE_Stats::sample (const ACE_INT32 value)
+{
+ if (overflow_)
+ {
+ // Had already overflowed.
+ return -1;
+ }
+ else
+ {
+ ++samples_;
+ if (samples_ == 0)
+ {
+ overflow_ = 1;
+ --samples_;
+ return -1;
+ }
+ else
+ {
+ ACE_UINT64 old_sum = sum_;
+ ACE_UINT64 old_sum_of_squares = sum_of_squares_;
+
+ sum_ += value;
+ sum_of_squares_ += value * value;
+
+ // Overflow checks.
+ if ((value >= 0 ? sum_ < old_sum : sum_ > old_sum) ||
+ sum_of_squares_ < old_sum_of_squares)
+ {
+ overflow_ = 1;
+ --samples_;
+ sum_ = old_sum;
+ sum_of_squares_ = old_sum_of_squares;
+ return -1;
+ }
+
+ if (value < min_)
+ min_ = value;
+
+ if (value > max_)
+ max_ = value;
+
+ return 0;
+ }
+ }
+}
+
+void
+ACE_Stats::mean (ACE_Stats_Value &mean,
+ const ACE_UINT32 scale_factor) const
+{
+ if (samples_ > 0)
+ {
+#if defined ACE_LACKS_LONGLONG_T
+ const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8);
+#endif /* ACE_LACKS_LONGLONG_T */
+
+ quotient (sum_ - ACE_STATS_INTERNAL_OFFSET,
+ samples_ * scale_factor,
+ mean);
+ }
+}
+
+void
+ACE_Stats::std_dev (ACE_Stats_Value &std_dev,
+ const ACE_UINT32 scale_factor) const
+{
+ if (samples_ <= 1)
+ {
+ std_dev.whole (0);
+ std_dev.fractional (0);
+ }
+ else
+ {
+#if defined ACE_LACKS_LONGLONG_T
+ const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8);
+#endif /* ACE_LACKS_LONGLONG_T */
+ // The sample standard deviation is:
+ //
+ // sqrt ((sum_of_squares_ - sums^2/samples_) / (samples_-1))
+
+ // Calculate the square of sums divided by the number of samples,
+ // carefully putting it into a 64-bit integer.
+ const ACE_UINT64 sums_squared_over_samples =
+ (sum_ - ACE_STATS_INTERNAL_OFFSET) *
+ ((sum_ - ACE_STATS_INTERNAL_OFFSET) / samples_);
+
+ // Divide the difference by (samples_ - 1), to get the variance.
+ // Don't scale the result, yet.
+ ACE_Stats_Value variance (std_dev.precision ());
+
+ quotient (sum_of_squares_ - sums_squared_over_samples,
+ samples_ - 1,
+ variance);
+
+ const ACE_UINT32 field = std_dev.fractional_field ();
+
+ // Take the square root of the variance to get the standard
+ // deviation.
+ ACE_UINT64 scaled_variance;
+ variance.scaled_value (scaled_variance);
+ // Scale up, once more, because we'll be taking the square root.
+ scaled_variance *= field;
+ ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ());
+ square_root (scaled_variance,
+ unscaled_standard_deviation);
+
+ // Unscale.
+ quotient (unscaled_standard_deviation,
+ scale_factor * field,
+ std_dev);
+ }
+}
+
+
+void
+ACE_Stats::reset (void)
+{
+#if defined ACE_LACKS_LONGLONG_T
+ const ACE_U_LongLong ACE_STATS_INTERNAL_OFFSET (0, 8);
+#endif /* ACE_LACKS_LONGLONG_T */
+
+ overflow_ = 0u;
+ samples_ = 0u;
+ min_ = 0x7FFFFFFF;
+ max_ = -0x80000000;
+ sum_ = ACE_STATS_INTERNAL_OFFSET;
+ sum_of_squares_ = 0u;
+}
+
+int
+ACE_Stats::print_summary (const u_int precision,
+ const ACE_UINT32 scale_factor,
+ FILE *file) const
+{
+ if (overflow_)
+ ACE_OS::fprintf (file,
+ ASYS_TEXT ("ACE_Stats::print_summary: "
+ "there was overflow!\n"));
+
+ // Build a format string, in case the C library doesn't support %*u.
+ char format[32];
+ ACE_OS::sprintf (format, ASYS_TEXT ("%%d.%%0%du"), precision);
+
+ ACE_Stats_Value u (precision);
+ mean (u, scale_factor);
+ char mean_string [128];
+ ACE_OS::sprintf (mean_string, format, u.whole (), u.fractional ());
+
+ ACE_Stats_Value sd (precision);
+ std_dev (sd, scale_factor);
+ char std_dev_string [128];
+ ACE_OS::sprintf (std_dev_string, format, sd.whole (), sd.fractional ());
+
+ ACE_Stats_Value minimum (precision), maximum (precision);
+ if (min_ != 0)
+ {
+ const ACE_UINT64 m (min_);
+ quotient (m, scale_factor, minimum);
+ }
+ if (max_ != 0)
+ {
+ const ACE_UINT64 m (max_);
+ quotient (m, scale_factor, maximum);
+ }
+ char min_string [128];
+ char max_string [128];
+ ACE_OS::sprintf (min_string, format,
+ minimum.whole (), minimum.fractional ());
+ ACE_OS::sprintf (max_string, format,
+ maximum.whole (), maximum.fractional ());
+
+ ACE_OS::fprintf (file, ASYS_TEXT ("samples: %u (%s - %s); mean: "
+ "%s; std dev: %s\n"),
+ samples (), min_string, max_string,
+ mean_string, std_dev_string);
+
+ return overflow_ ? -1 : 0;
+}
+
+void
+ACE_Stats::dump (void) const
+{
+ print_summary (3u);
+}
+
+void
+ACE_Stats::quotient (const ACE_UINT64 dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient)
+{
+ // The whole part of the division comes from simple integer division.
+ quotient.whole (divisor == 0 ? 0 : dividend / divisor);
+
+ if (quotient.precision () > 0 || divisor == 0)
+ {
+ const ACE_UINT32 field = quotient.fractional_field ();
+
+ // Fractional = (dividend % divisor) * 10^precision / divisor.
+ quotient.fractional (dividend % divisor * field / divisor);
+ }
+ else
+ // No fractional portion is requested, so don't bother
+ // calculating it.
+ quotient.fractional (0);
+}
+
+void
+ACE_Stats::quotient (const ACE_Stats_Value &dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient)
+{
+ // The whole part of the division comes from simple integer division.
+ quotient.whole (divisor == 0 ? 0 : dividend.whole () / divisor);
+
+ if (quotient.precision () > 0 || divisor == 0)
+ {
+ const ACE_UINT32 field = quotient.fractional_field ();
+
+ // Fractional = (dividend % divisor) * 10^precision / divisor.
+ quotient.fractional (dividend.whole () % divisor * field / divisor +
+ dividend.fractional () / divisor);
+ }
+ else
+ // No fractional portion is requested, so don't bother
+ // calculating it.
+ quotient.fractional (0);
+}
+
+void
+ACE_Stats::square_root (const ACE_UINT64 n,
+ ACE_Stats_Value &square_root)
+{
+ ACE_UINT32 floor = 0;
+ ACE_UINT32 ceiling = 0xFFFFFFFFu;
+ ACE_UINT32 mid = 0;
+ u_int i;
+
+ // The maximum number of iterations is log_2 (2^64) == 64.
+ for (i = 0; i < 64; ++i)
+ {
+ mid = (ceiling - floor) / 2 + floor;
+ if (floor == mid)
+ // Can't divide the interval any further.
+ break;
+ else
+ {
+ // Multiply carefully to avoid overflow.
+ ACE_UINT64 mid_squared = mid; mid_squared *= mid;
+ if (mid_squared == n)
+ break;
+ else if (mid_squared < n)
+ floor = mid;
+ else
+ ceiling = mid;
+ }
+ }
+
+ square_root.whole (mid);
+ ACE_UINT64 mid_squared = mid; mid_squared *= mid;
+
+ if (square_root.precision () && mid_squared < n)
+ {
+ // (mid * 10^precision + fractional)^2 ==
+ // n^2 * 10^(precision * 2)
+
+ const ACE_UINT32 field = square_root.fractional_field ();
+
+ floor = 0;
+ ceiling = field;
+ mid = 0;
+
+ // Do the 64-bit arithmetic carefully to avoid overflow.
+ ACE_UINT64 target = n;
+ target *= field;
+ target *= field;
+
+ ACE_UINT64 difference = 0;
+
+ for (i = 0; i < square_root.precision (); ++i)
+ {
+ mid = (ceiling - floor) / 2 + floor;
+
+ ACE_UINT64 current = square_root.whole () * field + mid;
+ current *= square_root.whole () * field + mid;
+
+ if (floor == mid)
+ {
+ difference = target - current;
+ break;
+ }
+ else if (current <= target)
+ floor = mid;
+ else
+ ceiling = mid;
+ }
+
+ // Check to see if the fractional part should be one greater.
+ ACE_UINT64 next = square_root.whole () * field + mid + 1;
+ next *= square_root.whole () * field + mid + 1;
+
+ square_root.fractional (next - target < difference ? mid + 1 : mid);
+ }
+ else
+ {
+ // No fractional portion is requested, so don't bother
+ // calculating it.
+ square_root.fractional (0);
+ }
+}
diff --git a/ace/Stats.h b/ace/Stats.h
new file mode 100644
index 00000000000..599214fcebb
--- /dev/null
+++ b/ace/Stats.h
@@ -0,0 +1,172 @@
+/* -*- C++ -*- */
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// ace
+//
+// = FILENAME
+// Stats.h
+//
+// = AUTHORS
+// David L. Levine
+//
+// ============================================================================
+
+#if !defined (ACE_STATS_H)
+#define ACE_STATS_H
+
+#include "ace/ACE.h"
+
+class ACE_Export ACE_Stats_Value
+{
+ // = TITLE
+ // Helper class for ACE_Stats.
+ //
+ // = DESCRIPTION
+ // Container struct for 64-bit signed quantity and its
+ // precision. It would be nicer to use a fixed-point class, but
+ // this is sufficient.
+public:
+ ACE_Stats_Value (const u_int precision);
+ // Constructor, which requires precision in terms of number of
+ // decimal digits. Don't use more than 9!
+
+ u_int precision (void) const;
+ // Accessor for precision.
+
+ void whole (const ACE_UINT32);
+ // Set the whole_ field.
+
+ ACE_UINT32 whole (void) const;
+ // Accessor for the whole_ field.
+
+ void fractional (const ACE_UINT32);
+ // Set the fractional_ field.
+
+ ACE_UINT32 fractional (void) const;
+ // Accessor for the fractional_ field.
+
+ ACE_UINT32 fractional_field (void) const;
+ // Calculates the maximum value of the fractional portion, given its
+ // precision.
+
+ void scaled_value (ACE_UINT64 &) const;
+ // Access the value as an _unsigned_ 64 bit quantity. It scales the
+ // value up by <precision> decimal digits, so that no precision will
+ // be lost. It assumes that <whole_> is >= 0.
+
+private:
+ ACE_UINT32 whole_;
+ // The integer portion of the value.
+
+ ACE_UINT32 fractional_;
+ // The fractional portion of the value.
+
+ const u_int precision_;
+ // The number of decimal digits of precision represented by
+ // <fractional_>.
+
+ ACE_UNIMPLEMENTED_FUNC (ACE_Stats_Value (void))
+};
+
+class ACE_Export ACE_Stats
+{
+ // = TITLE
+ // Provides simple statistical analysis.
+ //
+ // = DESCRIPTION
+ // Simple statistical analysis package. Prominent features are:
+ // 1) It does not use any floating point arithmetic.
+ // 2) It handles positive and/or negative sample values. The
+ // sample value type is ACE_INT32.
+ // 3) It uses 64 bit unsigned, but not 64 bit signed, quantities
+ // internally.
+ // 4) It checks for overflow of internal state variables.
+ // 5) It has no static variables of other than built-in types.
+public:
+ ACE_Stats (void);
+ // Default constructor.
+
+ int sample (const ACE_INT32 value);
+ // Provide a new sample. Returns 0 on success, -1 if internal overflow.
+ // If internal overflow is reached on this or any previous call, the
+ // state is not changed. Therefore, print_summary () can still be used.
+
+ ACE_UINT32 samples (void) const;
+ // Access the number of samples provided so far.
+
+ ACE_INT32 min_value (void) const;
+ // Value of the minimum sample provided so far.
+
+ ACE_INT32 max_value (void) const;
+ // Value of the maximum sample provided so far.
+
+ void mean (ACE_Stats_Value &mean,
+ const ACE_UINT32 scale_factor = 1) const;
+ // Access the mean of all samples provided so far. The fractional
+ // part is to the specified number of digits. E.g., 3 fractional
+ // digits specifies that fractional part is in thousandths.
+
+ void std_dev (ACE_Stats_Value &std_dev,
+ const ACE_UINT32 scale_factor = 1) const;
+ // Access the standard deviation, whole and fractional parts. See
+ // description of <mean> method for argument descriptions.
+
+ int print_summary (const u_int precision,
+ const ACE_UINT32 scale_factor = 1,
+ FILE * = stdout) const;
+ // Print summary statistics. If scale_factor is not 1, then the
+ // results are divided by it, i.e., each of the samples is scaled
+ // down by it. Returns -1 if internal overflow had been reached.
+ // The statistics will still be valid, but only for the samples
+ // received prior to the overflow.
+
+ void reset ();
+ // Initialize internal state.
+
+ void dump (void) const;
+ // Print summary statictics to stdout.
+
+ static void quotient (const ACE_UINT64 dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient);
+ // Utility division function, for ACE_UINT64 dividend.
+
+ static void quotient (const ACE_Stats_Value &dividend,
+ const ACE_UINT32 divisor,
+ ACE_Stats_Value &quotient);
+ // Utility division function, for ACE_Stats_Value dividend.
+
+ static void square_root (const ACE_UINT64 n,
+ ACE_Stats_Value &square_root);
+ // Sqrt function, which uses an oversimplified version of Newton's
+ // method. It's not fast, but it doesn't require floating point
+ // support.
+
+private:
+ u_int overflow_;
+ // Internal indication of whether there has been overflow.
+
+ ACE_UINT32 samples_;
+ // Number of samples.
+
+ ACE_INT32 min_;
+ // Minimum sample value.
+
+ ACE_INT32 max_;
+ // Maximum sample value.
+
+ ACE_UINT64 sum_;
+ // Running sum.
+
+ ACE_UINT64 sum_of_squares_;
+ // Running sum of squares.
+};
+
+#if defined (__ACE_INLINE__)
+#include "ace/Stats.i"
+#endif /* __ACE_INLINE__ */
+
+#endif /* ! ACE_STATS_H */
diff --git a/ace/Stats.i b/ace/Stats.i
new file mode 100644
index 00000000000..73c2c743d05
--- /dev/null
+++ b/ace/Stats.i
@@ -0,0 +1,79 @@
+/* -*- C++ -*- */
+// $Id$
+
+ACE_INLINE
+ACE_Stats_Value::ACE_Stats_Value (const u_int precision)
+ : whole_ (0),
+ fractional_ (0),
+ precision_ (precision)
+{
+}
+
+ACE_INLINE
+u_int
+ACE_Stats_Value::precision (void) const
+{
+ return precision_;
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::whole (const ACE_UINT32 value)
+{
+ whole_ = value;
+}
+
+ACE_INLINE
+ACE_UINT32
+ACE_Stats_Value::whole (void) const
+{
+ return whole_;
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::fractional (const ACE_UINT32 value)
+{
+ fractional_ = value;
+}
+
+ACE_INLINE
+ACE_UINT32
+ACE_Stats_Value::fractional (void) const
+{
+ return fractional_;
+}
+
+ACE_INLINE
+void
+ACE_Stats_Value::scaled_value (ACE_UINT64 &sv) const
+{
+ sv = whole () * fractional_field () + fractional ();
+}
+
+ACE_INLINE
+ACE_Stats::ACE_Stats (void)
+{
+ reset ();
+}
+
+ACE_INLINE
+ACE_UINT32
+ACE_Stats::samples (void) const
+{
+ return samples_;
+}
+
+ACE_INLINE
+ACE_INT32
+ACE_Stats::min_value (void) const
+{
+ return min_;
+}
+
+ACE_INLINE
+ACE_INT32
+ACE_Stats::max_value (void) const
+{
+ return max_;
+}