]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
cpu plugin: Implement `usage_global_count()`.
authorFlorian Forster <octo@collectd.org>
Tue, 9 Jan 2024 09:58:25 +0000 (10:58 +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 dc1d4e0e12490230c003cf437131c2eac420cb59..b893b32609f12956baebe70d5059632b9f212ddc 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -433,6 +433,7 @@ static void usage_finalize(usage_t *u) {
 
   gauge_t global_rate = 0;
   size_t cpu_num = u->states_num / STATE_MAX;
+  gauge_t state_ratio[STATE_MAX] = {0};
   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;
@@ -466,6 +467,11 @@ static void usage_finalize(usage_t *u) {
       }
     }
 
+    if (active->has_value) {
+      u->global[STATE_ACTIVE].rate += active->rate;
+      u->global[STATE_ACTIVE].has_value = true;
+    }
+
     /* With cpu_rate available, calculate a counter for each state that is
      * normalized to microseconds. I.e. all states of one CPU sum up to 1000000
      * us per second. */
@@ -481,19 +487,16 @@ static void usage_finalize(usage_t *u) {
         continue;
       }
 
-      gauge_t rate = 1000000.0 * us->rate / cpu_rate;
+      gauge_t ratio = us->rate / cpu_rate;
       value_t v = {0};
-      int status =
-          rate_to_value(&v, rate, &us->to_count, DS_TYPE_DERIVE, u->time);
+      int status = rate_to_value(&v, 1000000.0 * ratio, &us->to_count,
+                                 DS_TYPE_DERIVE, u->time);
       if (status == 0) {
         us->count = v.derive;
         us->has_count = true;
       }
-    }
 
-    if (active->has_value) {
-      u->global[STATE_ACTIVE].rate += active->rate;
-      u->global[STATE_ACTIVE].has_value = true;
+      state_ratio[s] += ratio;
     }
   }
 
@@ -502,13 +505,14 @@ static void usage_finalize(usage_t *u) {
 
     us->count = -1;
     if (!us->has_value) {
+      /* Ensure that us->to_count is initialized. */
+      rate_to_value(&(value_t){0}, 0.0, &us->to_count, DS_TYPE_DERIVE, u->time);
       continue;
     }
 
-    gauge_t rate = CDTIME_T_TO_DOUBLE(u->interval) * us->rate / global_rate;
     value_t v = {0};
-    int status =
-        rate_to_value(&v, rate, &us->to_count, DS_TYPE_DERIVE, u->time);
+    int status = rate_to_value(&v, 1000000.0 * state_ratio[s], &us->to_count,
+                               DS_TYPE_DERIVE, u->time);
     if (status == 0) {
       us->count = v.derive;
       us->has_count = true;
@@ -576,6 +580,13 @@ __attribute__((unused)) static derive_t usage_count(usage_t *u, size_t cpu,
   return us->count;
 }
 
+__attribute__((unused)) static derive_t usage_global_count(usage_t *u,
+                                                           state_t state) {
+  usage_finalize(u);
+
+  return u->global[state].count;
+}
+
 /* Takes the zero-index number of a CPU and makes sure that the module-global
  * cpu_states buffer is large enough. Returne ENOMEM on erorr. */
 static int cpu_states_alloc(size_t cpu_num) /* {{{ */
index 5b2cbb618fbb79dd336d0dde6eaa21d991549a98..e14739ae7ad1df9d92d938d4682a903f42d0ac69 100644 (file)
@@ -109,16 +109,20 @@ DEF_TEST(usage_ratio) {
 
 static bool expect_usage_count(derive_t want, derive_t got, size_t cpu,
                                state_t state) {
+  char prefix[510] = "usage_global_count(";
+  if (cpu != SIZE_MAX) {
+    snprintf(prefix, sizeof(prefix), "usage_count(cpu=%zu, ", cpu);
+  }
+
   bool ok = true;
   char msg[1024] = {0};
-  snprintf(msg, sizeof(msg), "usage_count(cpu=%zu, state=\"%s\") = %" PRId64,
-           cpu, cpu_state_names[state], got);
+  snprintf(msg, sizeof(msg), "%sstate=\"%s\") = %" PRId64, prefix,
+           cpu_state_names[state], got);
 
   derive_t diff = got - want;
   if (diff < -1 || diff > 1) {
-    snprintf(msg, sizeof(msg),
-             "usage_count(cpu=%zu, state=\"%s\") = %" PRId64 ", want %" PRId64,
-             cpu, cpu_state_names[state], got, want);
+    snprintf(msg, sizeof(msg), "%sstate=\"%s\") = %" PRId64 ", want %" PRId64,
+             prefix, cpu_state_names[state], got, want);
     ok = false;
   }
 
@@ -317,6 +321,70 @@ DEF_TEST(usage_global_ratio) {
   return 0;
 }
 
+/* sumup returns the sum of 1 + 2 + ... + n */
+static derive_t sumup(derive_t n) { return n * (n + 1) / 2; }
+
+DEF_TEST(usage_global_count) {
+  int ret = 0;
+  usage_t usage = {0};
+#define CPU_NUM 2
+
+  cdtime_t t0 = TIME_T_TO_CDTIME_T(100);
+  usage_init(&usage, t0);
+  for (size_t cpu = 0; cpu < CPU_NUM; cpu++) {
+    for (state_t s = 0; s < STATE_ACTIVE; s++) {
+      usage_record(&usage, cpu, s, 1000);
+    }
+  }
+  usage_finalize(&usage);
+
+  cdtime_t interval = TIME_T_TO_CDTIME_T(300);
+
+  cdtime_t t1 = t0 + interval;
+  usage_init(&usage, t1);
+  for (size_t cpu = 0; cpu < CPU_NUM; cpu++) {
+    for (state_t s = 0; s < STATE_ACTIVE; s++) {
+      derive_t increment = ((derive_t)cpu * STATE_ACTIVE) + ((derive_t)s);
+      usage_record(&usage, cpu, s, 1000 + increment);
+    }
+  }
+
+  derive_t cpu_increment[CPU_NUM] = {
+      sumup(10),
+      sumup(21) - sumup(10),
+  };
+
+  gauge_t state_ratio[STATE_MAX] = {0};
+  for (size_t cpu = 0; cpu < CPU_NUM; cpu++) {
+    for (state_t s = 0; s < STATE_ACTIVE; s++) {
+      derive_t increment = ((derive_t)cpu * STATE_ACTIVE) + ((derive_t)s);
+      gauge_t ratio = ((gauge_t)increment) / ((gauge_t)cpu_increment[cpu]);
+
+      state_ratio[s] += ratio;
+      if (s != STATE_IDLE) {
+        state_ratio[STATE_ACTIVE] += ratio;
+      }
+    }
+  }
+
+  for (state_t s = 0; s < STATE_MAX; s++) {
+    gauge_t want_time =
+        1000000.0 * CDTIME_T_TO_DOUBLE(interval) * state_ratio[s];
+    bool ok = expect_usage_count((derive_t)want_time,
+                                 usage_global_count(&usage, s), SIZE_MAX, s);
+    ret = ret || !ok;
+  }
+
+  gauge_t sum_ratio = 0;
+  for (state_t s = 0; s < STATE_ACTIVE; s++) {
+    sum_ratio += state_ratio[s];
+  }
+  EXPECT_EQ_DOUBLE(CPU_NUM, sum_ratio);
+
+  usage_reset(&usage);
+  return ret;
+}
+
 int main(void) {
   RUN_TEST(usage_rate);
   RUN_TEST(usage_ratio);
@@ -324,6 +392,7 @@ int main(void) {
   RUN_TEST(usage_active_rate);
   RUN_TEST(usage_global_rate);
   RUN_TEST(usage_global_ratio);
+  RUN_TEST(usage_global_count);
 
   END_TEST;
 }