]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
cpu plugin: Move aggregation into a central finalize() function.
authorFlorian Forster <octo@collectd.org>
Fri, 5 Jan 2024 10:16:23 +0000 (11:16 +0100)
committerFlorian Forster <octo@collectd.org>
Mon, 22 Jan 2024 15:07:57 +0000 (16:07 +0100)
src/cpu.c
src/cpu_test.c

index 3d364443bceb135b036212ccabc8eba2d153a19a..4472e044b00a62a172010371d59670209f17d683 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -343,8 +343,13 @@ typedef struct {
 
 typedef struct {
   cdtime_t time;
+  cdtime_t interval;
+  bool finalized;
+
   usage_state_t *states;
   size_t states_num;
+
+  usage_state_t global[STATE_MAX];
 } usage_t;
 
 __attribute__((unused)) static int usage_init(usage_t *u, cdtime_t now) {
@@ -352,10 +357,20 @@ __attribute__((unused)) static int usage_init(usage_t *u, cdtime_t now) {
     return EINVAL;
   }
 
+  if (u->time != 0 && u->time < now) {
+    u->interval = now - u->time;
+  }
   u->time = now;
+  u->finalized = false;
   for (size_t i = 0; i < u->states_num; i++) {
+    u->states[i].rate = 0;
     u->states[i].has_value = false;
   }
+  for (state_t s = 0; s < STATE_MAX; s++) {
+    u->global[s].rate = 0;
+    u->global[s].has_value = false;
+  }
+
   return 0;
 }
 
@@ -402,80 +417,85 @@ __attribute__((unused)) static int usage_record(usage_t *u, size_t cpu,
   return 0;
 }
 
-static gauge_t usage_rate(usage_t u, size_t cpu, state_t state);
-
-static gauge_t usage_active_rate(usage_t u, size_t cpu) {
-  size_t index = (cpu * STATE_MAX) + STATE_ACTIVE;
-  if (index >= u.states_num) {
-    return NAN;
+static void usage_finalize(usage_t *u) {
+  if (u->finalized) {
+    return;
   }
 
-  usage_state_t us = u.states[index];
-  if (us.has_value) {
-    return us.rate;
-  }
+  size_t cpu_num = u->states_num / STATE_MAX;
+  for (size_t cpu = 0; cpu < cpu_num; cpu++) {
+    size_t active_index = (cpu * STATE_MAX) + STATE_ACTIVE;
+    usage_state_t *active = u->states + active_index;
 
-  us.rate = 0;
-  for (state_t s = 0; s < STATE_IDLE; s++) {
-    gauge_t rate = usage_rate(u, cpu, s);
-    if (isnan(rate)) {
-      continue;
-    }
+    active->rate = 0;
+    active->has_value = false;
 
-    us.rate += rate;
-    us.has_value = true;
-  }
+    for (state_t s = 0; s < STATE_ACTIVE; s++) {
+      size_t index = (cpu * STATE_MAX) + s;
+      usage_state_t *us = u->states + index;
 
-  return us.has_value ? us.rate : NAN;
-}
+      if (!us->has_value) {
+        continue;
+      }
 
-static gauge_t usage_global_rate(usage_t u, state_t state) {
-  size_t cpu_num = u.states_num / STATE_MAX;
-  usage_state_t us = {0};
-  for (size_t i = 0; i < cpu_num; i++) {
-    gauge_t rate = usage_rate(u, i, state);
-    if (isnan(rate)) {
-      continue;
+      u->global[s].rate += us->rate;
+      u->global[s].has_value = true;
+
+      if (s != STATE_IDLE) {
+        active->rate += us->rate;
+        active->has_value = true;
+      }
     }
 
-    us.rate += rate;
-    us.has_value = true;
+    if (active->has_value) {
+      u->global[STATE_ACTIVE].rate += active->rate;
+      u->global[STATE_ACTIVE].has_value = true;
+    }
   }
 
-  return us.has_value ? us.rate : NAN;
+  u->finalized = true;
 }
 
-static gauge_t usage_rate(usage_t u, size_t cpu, state_t state) {
-  if (state == STATE_ACTIVE) {
-    return usage_active_rate(u, cpu);
-  }
+static gauge_t usage_rate(usage_t *u, size_t cpu, state_t state) {
+  usage_finalize(u);
 
   size_t index = (cpu * STATE_MAX) + state;
-  if (index >= u.states_num) {
+  if (index >= u->states_num) {
     return NAN;
   }
 
-  usage_state_t us = u.states[index];
+  usage_state_t us = u->states[index];
   return us.has_value ? us.rate : NAN;
 }
 
+__attribute__((unused)) static gauge_t usage_active_rate(usage_t *u,
+                                                         size_t cpu) {
+  return usage_rate(u, cpu, STATE_ACTIVE);
+}
+
+static gauge_t usage_global_rate(usage_t *u, state_t state) {
+  usage_finalize(u);
+
+  return u->global[state].has_value ? u->global[state].rate : NAN;
+}
+
 __attribute__((unused)) static void usage_reset(usage_t *u) {
   if (u == NULL) {
     return;
   }
   free(u->states);
-  u->states = NULL;
-  u->states_num = 0;
+  memset(u, 0, sizeof(*u));
 }
 
-__attribute__((unused)) static gauge_t usage_ratio(usage_t u, size_t cpu,
+__attribute__((unused)) static gauge_t usage_ratio(usage_t *u, size_t cpu,
                                                    state_t state) {
   gauge_t global_rate =
       usage_global_rate(u, STATE_ACTIVE) + usage_global_rate(u, STATE_IDLE);
   return usage_rate(u, cpu, state) / global_rate;
 }
 
-__attribute__((unused)) static gauge_t usage_global_ratio(usage_t u, state_t state) {
+__attribute__((unused)) static gauge_t usage_global_ratio(usage_t *u,
+                                                          state_t state) {
   gauge_t global_rate =
       usage_global_rate(u, STATE_ACTIVE) + usage_global_rate(u, STATE_IDLE);
   return usage_global_rate(u, state) / global_rate;
index 08fe87019d498bd4f77475de42d23b1dc76d271b..df4c577bf28f6941c508bf1d0684528f2551125d 100644 (file)
@@ -32,8 +32,8 @@ DEF_TEST(usage_rate) {
   usage_record(&usage, 0, STATE_USER, count_t0);
 
   // Unable to calculate a rate with a single data point.
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_USER));
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_ACTIVE));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_USER));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_ACTIVE));
 
   cdtime_t t1 = t0 + TIME_T_TO_CDTIME_T(10);
   derive_t count_t1 = count_t0 + 100;
@@ -42,15 +42,15 @@ DEF_TEST(usage_rate) {
   usage_init(&usage, t1);
   usage_record(&usage, 0, STATE_USER, count_t1);
 
-  EXPECT_EQ_DOUBLE(want_rate, usage_rate(usage, 0, STATE_USER));
-  EXPECT_EQ_DOUBLE(want_rate, usage_rate(usage, 0, STATE_ACTIVE));
+  EXPECT_EQ_DOUBLE(want_rate, usage_rate(&usage, 0, STATE_USER));
+  EXPECT_EQ_DOUBLE(want_rate, usage_rate(&usage, 0, STATE_ACTIVE));
 
   // States that we have not set should be NAN
   for (state_t s = 0; s < STATE_ACTIVE; s++) {
     if (s == STATE_USER) {
       continue;
     }
-    EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, s));
+    EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, s));
   }
 
   usage_reset(&usage);
@@ -87,17 +87,17 @@ DEF_TEST(usage_ratio) {
         active_increment += increment;
       }
       gauge_t want_ratio = ((gauge_t)increment) / ((gauge_t)global_increment);
-      EXPECT_EQ_DOUBLE(want_ratio, usage_ratio(usage, cpu, s));
+      EXPECT_EQ_DOUBLE(want_ratio, usage_ratio(&usage, cpu, s));
     }
     gauge_t want_active_ratio =
         ((gauge_t)active_increment) / ((gauge_t)global_increment);
-    EXPECT_EQ_DOUBLE(want_active_ratio, usage_ratio(usage, cpu, STATE_ACTIVE));
+    EXPECT_EQ_DOUBLE(want_active_ratio, usage_ratio(&usage, cpu, STATE_ACTIVE));
   }
 
   gauge_t sum = 0;
   for (size_t cpu = 0; cpu < 4; cpu++) {
     for (state_t s = 0; s < STATE_ACTIVE; s++) {
-      gauge_t rate = usage_ratio(usage, cpu, s);
+      gauge_t rate = usage_ratio(&usage, cpu, s);
       sum += rate;
     }
   }
@@ -121,11 +121,11 @@ DEF_TEST(usage_active_rate) {
   usage_record(&usage, 0, STATE_IDLE, idle_t0);
 
   // Unable to calculate a rate with a single data point.
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_USER));
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_SYSTEM));
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_IDLE));
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_ACTIVE));
-  EXPECT_EQ_DOUBLE(NAN, usage_active_rate(usage, 0));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_USER));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_SYSTEM));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_IDLE));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_ACTIVE));
+  EXPECT_EQ_DOUBLE(NAN, usage_active_rate(&usage, 0));
 
   cdtime_t t1 = t0 + TIME_T_TO_CDTIME_T(10);
   derive_t user_t1 = user_t0 + 200;
@@ -142,11 +142,11 @@ DEF_TEST(usage_active_rate) {
   usage_record(&usage, 0, STATE_SYSTEM, syst_t1);
   usage_record(&usage, 0, STATE_IDLE, idle_t1);
 
-  EXPECT_EQ_DOUBLE(want_user_rate, usage_rate(usage, 0, STATE_USER));
-  EXPECT_EQ_DOUBLE(want_syst_rate, usage_rate(usage, 0, STATE_SYSTEM));
-  EXPECT_EQ_DOUBLE(want_idle_rate, usage_rate(usage, 0, STATE_IDLE));
-  EXPECT_EQ_DOUBLE(want_active_rate, usage_rate(usage, 0, STATE_ACTIVE));
-  EXPECT_EQ_DOUBLE(want_active_rate, usage_active_rate(usage, 0));
+  EXPECT_EQ_DOUBLE(want_user_rate, usage_rate(&usage, 0, STATE_USER));
+  EXPECT_EQ_DOUBLE(want_syst_rate, usage_rate(&usage, 0, STATE_SYSTEM));
+  EXPECT_EQ_DOUBLE(want_idle_rate, usage_rate(&usage, 0, STATE_IDLE));
+  EXPECT_EQ_DOUBLE(want_active_rate, usage_rate(&usage, 0, STATE_ACTIVE));
+  EXPECT_EQ_DOUBLE(want_active_rate, usage_active_rate(&usage, 0));
 
   usage_reset(&usage);
   return 0;
@@ -164,10 +164,10 @@ DEF_TEST(usage_global_rate) {
   usage_record(&usage, 1, STATE_USER, cpu1_t0);
 
   // Unable to calculate a rate with a single data point.
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 0, STATE_USER));
-  EXPECT_EQ_DOUBLE(NAN, usage_rate(usage, 1, STATE_USER));
-  EXPECT_EQ_DOUBLE(NAN, usage_global_rate(usage, STATE_USER));
-  EXPECT_EQ_DOUBLE(NAN, usage_global_rate(usage, STATE_ACTIVE));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 0, STATE_USER));
+  EXPECT_EQ_DOUBLE(NAN, usage_rate(&usage, 1, STATE_USER));
+  EXPECT_EQ_DOUBLE(NAN, usage_global_rate(&usage, STATE_USER));
+  EXPECT_EQ_DOUBLE(NAN, usage_global_rate(&usage, STATE_ACTIVE));
 
   cdtime_t t1 = t0 + TIME_T_TO_CDTIME_T(10);
   derive_t cpu0_t1 = cpu0_t0 + 300;
@@ -181,10 +181,10 @@ DEF_TEST(usage_global_rate) {
   usage_record(&usage, 0, STATE_USER, cpu0_t1);
   usage_record(&usage, 1, STATE_USER, cpu1_t1);
 
-  EXPECT_EQ_DOUBLE(want_cpu0_rate, usage_rate(usage, 0, STATE_USER));
-  EXPECT_EQ_DOUBLE(want_cpu1_rate, usage_rate(usage, 1, STATE_USER));
-  EXPECT_EQ_DOUBLE(want_global_rate, usage_global_rate(usage, STATE_USER));
-  EXPECT_EQ_DOUBLE(want_global_rate, usage_global_rate(usage, STATE_ACTIVE));
+  EXPECT_EQ_DOUBLE(want_cpu0_rate, usage_rate(&usage, 0, STATE_USER));
+  EXPECT_EQ_DOUBLE(want_cpu1_rate, usage_rate(&usage, 1, STATE_USER));
+  EXPECT_EQ_DOUBLE(want_global_rate, usage_global_rate(&usage, STATE_USER));
+  EXPECT_EQ_DOUBLE(want_global_rate, usage_global_rate(&usage, STATE_ACTIVE));
 
   usage_reset(&usage);
   return 0;
@@ -221,7 +221,7 @@ DEF_TEST(usage_global_ratio) {
     }
     gauge_t want_state_ratio =
         ((gauge_t)state_increment) / ((gauge_t)global_increment);
-    EXPECT_EQ_DOUBLE(want_state_ratio, usage_global_ratio(usage, s));
+    EXPECT_EQ_DOUBLE(want_state_ratio, usage_global_ratio(&usage, s));
 
     if (s != STATE_IDLE) {
       global_active_increment += state_increment;
@@ -230,10 +230,10 @@ DEF_TEST(usage_global_ratio) {
   gauge_t want_global_active_ratio =
       ((gauge_t)global_active_increment) / ((gauge_t)global_increment);
   EXPECT_EQ_DOUBLE(want_global_active_ratio,
-                   usage_global_ratio(usage, STATE_ACTIVE));
+                   usage_global_ratio(&usage, STATE_ACTIVE));
 
   EXPECT_EQ_DOUBLE(1.0 - want_global_active_ratio,
-                   usage_global_ratio(usage, STATE_IDLE));
+                   usage_global_ratio(&usage, STATE_IDLE));
 
   usage_reset(&usage);
   return 0;