From: Florian Forster Date: Fri, 5 Jan 2024 06:59:57 +0000 (+0100) Subject: cpu plugin: Add a very simple `usage_t` type for aggregation. X-Git-Tag: 6.0.0-rc0~5^2~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f91837f0dfb30ae9c2a3873cf22b93f477f6d73a;p=thirdparty%2Fcollectd.git cpu plugin: Add a very simple `usage_t` type for aggregation. --- diff --git a/Makefile.am b/Makefile.am index 8829ac52c..685268af3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/src/cpu.c b/src/cpu.c index c1b47836e..ebf67cd6d 100644 --- 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 index 000000000..8f400923f --- /dev/null +++ b/src/cpu_test.c @@ -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 + **/ + +#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; +}