]> xenbits.xensource.com Git - people/dstodden/blktap.git/commitdiff
CA-27472: Limit dispersion tracking to timevals.
authorDaniel Stodden <daniel.stodden@citrix.com>
Fri, 10 Apr 2009 03:49:40 +0000 (20:49 -0700)
committerDaniel Stodden <daniel.stodden@citrix.com>
Fri, 10 Apr 2009 03:49:40 +0000 (20:49 -0700)
Get rid of the FPU stuff. We're only tracking time this way. The
floats lack the necessary precision to track absolute time, and fixed
integer arithmetic is nicer anyways.

drivers/tapdisk-vbd-stats.h
drivers/tapdisk-vbd.c

index ee400dd9c79a24b6049d622749d729441a1db618..eb49637e9fe9873d5966aa6975a5099fe0ea561e 100644 (file)
  */
 
 #include <math.h>
+#include <time.h>
+#include <string.h>
+#include <sys/time.h>
+#include <limits.h>
 
 /*
- * Incrementally track mean and standard deviation on sample sequences.
+ * Incrementally track mean and standard deviation on timer samples.
  */
 
 struct dispersion {
-       int     k;              /* number of samples */
-       float   max, min;
-       float   mean, S;        /* mean/stdev accumulators */
+       int            k;              /* number of samples */
+       struct timeval max, min;
+       struct timeval mean;
+       double         S;              /* stdev accumulator */
 };
 
+#define TV_FLT(_tv)                                                    \
+       ((double)(_tv).tv_sec + (double)(_tv).tv_usec / 1000000)
+
+#define FLT_TV(_f) ({                                                  \
+       struct timeval __tv;                                            \
+       time_t __s = (_f);                                              \
+       __tv.tv_sec = __s;                                              \
+       __tv.tv_usec = ((_f) - __s) * 1000000;                          \
+       __tv;                                                           \
+})
+
+static const struct timeval __tv_zero = { 0, 0 };
+
 #define  TD_STATS_MEAN(_st) ((_st)->mean)
-#define   TD_STATS_VAR(_st) ((_st)->k > 1 ? (_st)->S / ((_st)->k - 1) : 0)
-#define TD_STATS_STDEV(_st) sqrt(TD_STATS_VAR(_st))
-#define   TD_STATS_MIN(_st) ((_st)->k > 0 ? (_st)->min : 0.0)
-#define   TD_STATS_MAX(_st) ((_st)->k > 0 ? (_st)->max : 0.0)
+
+#define __TD_STATS_VAR(_st) ((_st)->k > 1 ? (_st)->S / ((_st)->k - 1) : 0.0)
+#define   TD_STATS_VAR(_st) FLT_TV(TD_STATS_VAR(_st))
+#define TD_STATS_STDEV(_st) FLT_TV(sqrt(__TD_STATS_VAR(_st)))
+
+#define   TD_STATS_MIN(_st) ((_st)->k > 0 ? (_st)->min : __tv_zero)
+#define   TD_STATS_MAX(_st) ((_st)->k > 0 ? (_st)->max : __tv_zero)
 
 static inline void
 td_dispersion_init(struct dispersion *st)
 {
-       st->k    = 0;
-       st->min  = INFINITY;
-       st->max  = -INFINITY;
-       st->mean = 0.0;
-       st->S    = 0.0;
+       memset(st, 0, sizeof(struct dispersion));
+       st->min.tv_sec   = LONG_MAX;
+       st->max.tv_sec   = LONG_MIN;
+}
+
+static inline void
+timerdiv(struct timeval *tv, long k, struct timeval *q)
+{
+       time_t rest;
+
+       q->tv_sec  = tv->tv_sec / k;
+       rest       = tv->tv_sec % k;
+       q->tv_usec = (tv->tv_usec + rest * 1000000) / k;
+
+       if (q->tv_usec < 0) {
+               q->tv_usec += 1000000;
+               q->tv_sec  -= 1;
+       }
 }
 
 static inline void
-td_dispersion_add(struct dispersion *st, float val)
+td_dispersion_add(struct dispersion *st, struct timeval *tv)
 {
-       float _mean = st->mean;
+       struct timeval _mean, delta1, delta2;
 
        ++st->k;
 
-       if (val < st->min)
-               st->min = val;
+       if (timercmp(tv, &st->min, <))
+               st->min = *tv;
 
-       if (val > st->max)
-               st->max = val;
+       if (timercmp(&st->max, tv, <))
+               st->max = *tv;
 
        /*
         * The mean is a simple recurrence:
         * M(1) := x(1); M(k) := M(k-1) + (x(k) - M(k-1)) / k
         */
-       st->mean += (val - _mean) / st->k;
+
+       _mean = st->mean;
+
+       timersub(tv, &_mean, &delta1);
+       timerdiv(&delta1, st->k, &delta2);
+
+       timeradd(&_mean, &delta2, &st->mean);
 
        /*
         * Standard deviation is, uuhm, almost as simple (TAOCP Vol.2 4.2.2).
         * S(1) := 0; S(k) := S(k-1) + (x(k) - M(k-1)) * (x(k) - M(k))
         */
-       st->S += (val - _mean) * (val - st->mean);
+
+       timersub(tv, &st->mean, &delta2);
+
+       st->S += TV_FLT(delta1) * TV_FLT(delta2);
+}
+
+static inline void
+td_dispersion_add_now(struct dispersion *st)
+{
+       struct timeval now;
+
+       gettimeofday(&now, NULL);
+
+       td_dispersion_add(st, &now);
 }
index bd3bb1955ff21c592e10c0cfc7e072efa75ee9cb..bc504f05ca8de641c2191c4c252b794b0d484ddb 100644 (file)
@@ -847,6 +847,7 @@ static int
 tapdisk_vbd_shutdown(td_vbd_t *vbd)
 {
        int new, pending, failed, completed;
+       struct timeval avg, stdev;
 
        if (!list_empty(&vbd->pending_requests))
                return -EAGAIN;
@@ -864,10 +865,15 @@ tapdisk_vbd_shutdown(td_vbd_t *vbd)
                vbd->ts.tv_sec, vbd->ts.tv_usec,
                vbd->errors, vbd->retries, vbd->received, vbd->returned,
                vbd->kicked, vbd->kicks_in, vbd->kicks_out);
-       DPRINTF("failure cnt: %d ttl min: %.3f max: %.3f avg: %.3f stdev: %.3f\n",
+       avg   = TD_STATS_MEAN(&vbd->failure_ttl);
+       stdev = TD_STATS_STDEV(&vbd->failure_ttl);
+       DPRINTF("failure cnt: %d ttl min: %lu max: %lu "
+               "avg: %lu.%03lu stdev: %lu.%03lu\n",
                vbd->failure_ttl.k,
-               TD_STATS_MIN(&vbd->failure_ttl), TD_STATS_MAX(&vbd->failure_ttl),
-               TD_STATS_MEAN(&vbd->failure_ttl), TD_STATS_STDEV(&vbd->failure_ttl));
+               TD_STATS_MIN(&vbd->failure_ttl).tv_sec,
+               TD_STATS_MAX(&vbd->failure_ttl).tv_sec,
+               avg.tv_sec, avg.tv_usec / 1000,
+               stdev.tv_sec, stdev.tv_usec / 1000);
 
        tapdisk_vbd_close_vdi(vbd);
        tapdisk_ipc_write(&vbd->ipc, TAPDISK_MESSAGE_CLOSE_RSP);
@@ -1178,14 +1184,11 @@ static void
 tapdisk_vbd_failure_stats_add(td_vbd_t *vbd, td_vbd_request_t *vreq)
 {
        struct timeval now, delta;
-       float fdelta;
 
        gettimeofday(&now, NULL);
        timersub(&now, &vbd->ts, &delta);
-       
-       fdelta = (float)delta.tv_sec + (float)delta.tv_usec / 1000000;
 
-       td_dispersion_add(&vbd->failure_ttl, fdelta);
+       td_dispersion_add(&vbd->failure_ttl, &delta);
 }
 
 static void