]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
cpu plugin: Add a very simple `usage_t` type for aggregation.
authorFlorian Forster <octo@collectd.org>
Fri, 5 Jan 2024 06:59:57 +0000 (07:59 +0100)
committerFlorian Forster <octo@collectd.org>
Mon, 22 Jan 2024 15:07:57 +0000 (16:07 +0100)
Makefile.am
src/cpu.c
src/cpu_test.c [new file with mode: 0644]

index 8829ac52c06d8aec1c824bc2693492d20c895176..685268af34fde62f34da89ae1c81f6e4f51582b0 100644 (file)
@@ -936,6 +936,10 @@ endif
 if BUILD_WITH_PERFSTAT
 cpu_la_LIBADD += -lperfstat
 endif
+
+check_PROGRAMS += test_plugin_cpu
+test_plugin_cpu_SOURCES = src/cpu_test.c
+test_plugin_cpu_LDADD = libplugin_mock.la
 endif
 
 if BUILD_PLUGIN_CPUFREQ
index c1b47836e2bafb222dd96fc3883dfc361c5362d0..ebf67cd6d6daf9693b565b29f050cff20a34f14c 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -335,6 +335,95 @@ static int init(void) {
   return 0;
 } /* int init */
 
+typedef struct {
+  value_to_rate_state_t conv;
+  gauge_t rate;
+  bool has_value;
+} usage_state_t;
+
+typedef struct {
+  cdtime_t time;
+  usage_state_t *states;
+  size_t states_num;
+} usage_t;
+
+__attribute__((unused)) static int usage_init(usage_t *u, cdtime_t now) {
+  if (u == NULL || now == 0) {
+    return EINVAL;
+  }
+
+  u->time = now;
+  for (size_t i = 0; i < u->states_num; i++) {
+    u->states[i].has_value = false;
+  }
+  return 0;
+}
+
+static int usage_resize(usage_t *u, size_t cpu) {
+  size_t num = (cpu + 1) * STATE_MAX;
+  if (u->states_num >= num) {
+    return 0;
+  }
+
+  usage_state_t *ptr = realloc(u->states, sizeof(*u->states) * num);
+  if (ptr == NULL) {
+    return ENOMEM;
+  }
+  u->states = ptr;
+  ptr = u->states + u->states_num;
+  memset(ptr, 0, sizeof(*ptr) * (num - u->states_num));
+  u->states_num = num;
+
+  return 0;
+}
+
+__attribute__((unused)) static int usage_record(usage_t *u, size_t cpu,
+                                                state_t state, derive_t count) {
+  if (u == NULL || state >= STATE_ACTIVE) {
+    return EINVAL;
+  }
+
+  int status = usage_resize(u, cpu);
+  if (status != 0) {
+    return status;
+  }
+
+  size_t index = (cpu * STATE_MAX) + state;
+  assert(index < u->states_num);
+  usage_state_t *us = u->states + index;
+
+  status = value_to_rate(&us->rate, (value_t){.derive = count}, DS_TYPE_DERIVE,
+                         u->time, &us->conv);
+  if (status != 0) {
+    return status;
+  }
+
+  us->has_value = true;
+  return 0;
+}
+
+__attribute__((unused)) static gauge_t usage_rate(usage_t u, size_t cpu,
+                                                  state_t state) {
+  size_t index = (cpu * STATE_MAX) + state;
+  if (index >= u.states_num) {
+    return NAN;
+  }
+
+  if (!u.states[index].has_value) {
+    return NAN;
+  }
+  return u.states[index].rate;
+}
+
+__attribute__((unused)) static void usage_reset(usage_t *u) {
+  if (u == NULL) {
+    return;
+  }
+  free(u->states);
+  u->states = NULL;
+  u->states_num = 0;
+}
+
 /* 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) /* {{{ */
diff --git a/src/cpu_test.c b/src/cpu_test.c
new file mode 100644 (file)
index 0000000..8f40092
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * collectd - src/cpu_test.c
+ * Copyright (C) 2024      Florian octo Forster
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ *
+ * Authors:
+ *   Florian octo Forster <octo at collectd.org>
+ **/
+
+#include "cpu.c" /* sic */
+#include "testing.h"
+
+DEF_TEST(usage) {
+  usage_t usage = {0};
+
+  cdtime_t t0 = TIME_T_TO_CDTIME_T(100);
+  derive_t count_t0 = 3000;
+
+  usage_init(&usage, t0);
+  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));
+
+  cdtime_t t1 = t0 + TIME_T_TO_CDTIME_T(10);
+  derive_t count_t1 = count_t0 + 100;
+  gauge_t want_rate = 100.0 / 10.0;
+
+  usage_init(&usage, t1);
+  usage_record(&usage, 0, STATE_USER, count_t1);
+
+  EXPECT_EQ_DOUBLE(want_rate, usage_rate(usage, 0, STATE_USER));
+
+  usage_reset(&usage);
+  return 0;
+}
+
+int main(void) {
+  RUN_TEST(usage);
+
+  END_TEST;
+}