*/
#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);
}
tapdisk_vbd_shutdown(td_vbd_t *vbd)
{
int new, pending, failed, completed;
+ struct timeval avg, stdev;
if (!list_empty(&vbd->pending_requests))
return -EAGAIN;
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);
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