]> git.ipfire.org Git - collecty.git/commitdiff
modules: Add context switches
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 28 Sep 2025 10:53:00 +0000 (10:53 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 28 Sep 2025 10:53:00 +0000 (10:53 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/daemon/modules.c
src/daemon/modules/contextswitches.c [new file with mode: 0644]
src/daemon/modules/contextswitches.h [new file with mode: 0644]

index 7587c5664dc43e83210888a01085df073f0d5188..330b22aec3a14952bf964376454eb16b2d42f19b 100644 (file)
@@ -102,6 +102,8 @@ dist_collectyd_SOURCES = \
        src/daemon/module.h \
        src/daemon/modules.c \
        src/daemon/modules.h \
+       src/daemon/modules/contextswitches.c \
+       src/daemon/modules/contextswitches.h \
        src/daemon/modules/loadavg.c \
        src/daemon/modules/loadavg.h \
        src/daemon/queue.c \
index eead3822cb00c17ba2ac59a918461e24c4c97e86..da13f85d3dc2517f74cb9da4dd1eb43d93c16eb9 100644 (file)
 #include "modules.h"
 
 // Load all modules
+#include "modules/contextswitches.h"
 #include "modules/loadavg.h"
 
 // Register all modules
 static const collecty_module_methods* modules[] = {
+       &contextswitches_module,
        &loadavg_module,
        NULL,
 };
diff --git a/src/daemon/modules/contextswitches.c b/src/daemon/modules/contextswitches.c
new file mode 100644 (file)
index 0000000..4b1cc72
--- /dev/null
@@ -0,0 +1,133 @@
+/*#############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2025 IPFire Development Team                                  #
+#                                                                             #
+# 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, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# 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, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include <errno.h>
+#include <linux/perf_event.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "../ctx.h"
+#include "../module.h"
+#include "contextswitches.h"
+
+static int perf_event_open(struct perf_event_attr* hw_event,
+               pid_t pid, int cpu, int group_fd, unsigned long flags) {
+       return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
+}
+
+static unsigned int num_cpus = 0;
+static int* perf_eventfds = NULL;
+
+static int contextswitches_init(collecty_ctx* ctx) {
+       struct perf_event_attr event = {
+               .type     = PERF_TYPE_SOFTWARE,
+               .config   = PERF_COUNT_SW_CONTEXT_SWITCHES,
+               .size     = sizeof(event),
+               .disabled = 0,
+               .exclude_kernel = 0,
+               .exclude_hv     = 0,
+       };
+       int fd = -EBADF;
+
+       // Detect the total number of processors
+       if (!num_cpus)
+               num_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       // Allocate an array for the file descriptors
+       perf_eventfds = calloc(num_cpus, sizeof(*perf_eventfds));
+       if (!perf_eventfds)
+               return -errno;
+
+       // Initialize the array
+       for (unsigned int i = 0; i < num_cpus; i++)
+               perf_eventfds[i] = -EBADF;
+
+       // Keep a perf file descriptor open for each CPU core
+       for (unsigned int i = 0; i < num_cpus; i++) {
+               fd = perf_event_open(&event, -1, i, -1, 0);
+               if (fd < 0) {
+                       ERROR(ctx, "Failed run perf_event_open() for CPU %d: %m\n", i);
+                       return -errno;
+               }
+
+               // Store the file descriptor
+               perf_eventfds[i] = fd;
+       }
+
+       return 0;
+}
+
+static int contextswitches_free(collecty_ctx* ctx) {
+       // Close any open file descriptors
+       if (perf_eventfds) {
+               for (unsigned int i = 0; i < num_cpus; i++) {
+                       if (perf_eventfds[i] >= 0)
+                               close(perf_eventfds[i]);
+               }
+               free(perf_eventfds);
+       }
+
+       return 0;
+}
+
+static int contextswitches_collect(collecty_ctx* ctx, collecty_module* module) {
+       long long total = 0;
+       uint64_t count = 0;
+       int fd = -EBADF;
+       int r;
+
+       // Read the number of context switches per CPU and add them up
+       for (unsigned int i = 0; i < num_cpus; i++) {
+               fd = perf_eventfds[i];
+
+               // Abort if we are missing some file descriptors
+               if (fd < 0)
+                       return -EBADFD;
+
+               // Read the integer
+               r = read(fd, &count, sizeof(count));
+               if (r < 0) {
+                       ERROR(ctx, "Failed to read the number of context switches: %m\n");
+                       return -errno;
+               }
+
+               // Sum up all values
+               total += count;
+       }
+
+       // Submit the values
+       return collecty_module_submit(module, NULL, "%lld", total);
+}
+
+const collecty_module_methods contextswitches_module = {
+       .name    = "contextswitches",
+
+       // RRD Data Sources
+       .rrd_dss = {
+               { "ctxt", "DERIVE", 0, -1, },
+               { NULL },
+       },
+
+       // Methods
+       .init    = contextswitches_init,
+       .free    = contextswitches_free,
+       .collect = contextswitches_collect,
+};
diff --git a/src/daemon/modules/contextswitches.h b/src/daemon/modules/contextswitches.h
new file mode 100644 (file)
index 0000000..d363de6
--- /dev/null
@@ -0,0 +1,28 @@
+/*#############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2025 IPFire Development Team                                  #
+#                                                                             #
+# 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, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# 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, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef COLLECTY_MODULE_CONTEXTSWITCHES_H
+#define COLLECTY_MODULE_CONTEXTSWITCHES_H
+
+#include "../module.h"
+
+extern const collecty_module_methods contextswitches_module;
+
+#endif /* COLLECTY_MODULE_CONTEXTSWITCHES_H */