src/daemon/common.c: Fix handling of counter_t in value_to_rate().
authorFlorian Forster <octo@collectd.org>
Sun, 28 Jun 2015 13:00:49 +0000 (15:00 +0200)
committerFlorian Forster <octo@collectd.org>
Sun, 28 Jun 2015 13:00:49 +0000 (15:00 +0200)
Also fixes an off-by-one error in counter_diff() and adds a unit test for
the function.

src/daemon/common.c
src/daemon/common_test.c
src/testing.h

index 9e0648c..73dd277 100644 (file)
@@ -1362,10 +1362,9 @@ counter_t counter_diff (counter_t old_value, counter_t new_value)
        if (old_value > new_value)
        {
                if (old_value <= 4294967295U)
-                       diff = (4294967295U - old_value) + new_value;
+                       diff = (4294967295U - old_value) + new_value + 1;
                else
-                       diff = (18446744073709551615ULL - old_value)
-                               + new_value;
+                       diff = (18446744073709551615ULL - old_value) + new_value + 1;
        }
        else
        {
@@ -1516,7 +1515,8 @@ int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */
        }
        else if (ds_type == DS_TYPE_COUNTER)
        {
-               ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval;
+               counter_t diff = counter_diff (state->last_value.counter, (counter_t) value);
+               ret_rate->gauge = ((gauge_t) diff) / ((gauge_t) interval);
                state->last_value.counter = (counter_t) value;
        }
        else if (ds_type == DS_TYPE_ABSOLUTE)
index f40b2b1..b1701bc 100644 (file)
@@ -338,6 +338,43 @@ DEF_TEST(parse_values)
   return (0);
 }
 
+DEF_TEST(value_to_rate)
+{
+  struct {
+    time_t t0;
+    time_t t1;
+    int ds_type;
+    value_t v0;
+    value_t v1;
+    gauge_t want;
+  } cases[] = {
+    { 0, 10, DS_TYPE_DERIVE,  {.derive  =    0}, {.derive = 1000},   NAN},
+    {10, 20, DS_TYPE_DERIVE,  {.derive  = 1000}, {.derive = 2000}, 100.0},
+    {20, 30, DS_TYPE_DERIVE,  {.derive  = 2000}, {.derive = 1800}, -20.0},
+    { 0, 10, DS_TYPE_COUNTER, {.counter =    0}, {.counter = 1000},   NAN},
+    {10, 20, DS_TYPE_COUNTER, {.counter = 1000}, {.counter = 5000}, 400.0},
+    /* 32bit wrap-around. */
+    {20, 30, DS_TYPE_COUNTER, {.counter = 4294967238}, {.counter =   42}, 10.0},
+    {30, 40, DS_TYPE_COUNTER, {.counter = 18446744073709551558ULL}, {.counter =   42}, 10.0},
+  };
+  size_t i;
+
+  for (i = 0; i < STATIC_ARRAY_SIZE (cases); i++) {
+    value_to_rate_state_t state = { cases[i].v0, TIME_T_TO_CDTIME_T (cases[i].t0) };
+    value_t got;
+
+    if (cases[i].t0 == 0) {
+      OK(value_to_rate (&got, cases[i].v1.derive, &state, cases[i].ds_type, TIME_T_TO_CDTIME_T (cases[i].t1)) == EAGAIN);
+      continue;
+    }
+
+    OK(value_to_rate (&got, cases[i].v1.derive, &state, cases[i].ds_type, TIME_T_TO_CDTIME_T (cases[i].t1)) == 0);
+    DBLEQ(cases[i].want, got.gauge);
+  }
+
+  return 0;
+}
+
 int main (void)
 {
   RUN_TEST(sstrncpy);
@@ -349,6 +386,7 @@ int main (void)
   RUN_TEST(escape_string);
   RUN_TEST(strunescape);
   RUN_TEST(parse_values);
+  RUN_TEST(value_to_rate);
 
   END_TEST;
 }
index 5df1b83..4056311 100644 (file)
@@ -54,6 +54,15 @@ static int check_count__ = 0;
   printf ("ok %i - %s evaluates to \"%s\"\n", ++check_count__, #actual, expect); \
 } while (0)
 
+#define DBLEQ(expect, actual) do { \
+  if ((isnan (expect) && !isnan (actual)) || ((expect) != (actual))) {\
+    printf ("not ok %i - %s incorrect: expected %.15g, got %.15g\n", \
+        ++check_count__, #actual, expect, actual); \
+    return (-1); \
+  } \
+  printf ("ok %i - %s evaluates to %.15g\n", ++check_count__, #actual, expect); \
+} while (0)
+
 #define CHECK_NOT_NULL(expr) do { \
   void *ptr_; \
   ptr_ = (expr); \