summaryrefslogtreecommitdiffstats
path: root/collectors/debugfs.plugin/sys_devices_virtual_powercap.c
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/debugfs.plugin/sys_devices_virtual_powercap.c')
-rw-r--r--collectors/debugfs.plugin/sys_devices_virtual_powercap.c217
1 files changed, 217 insertions, 0 deletions
diff --git a/collectors/debugfs.plugin/sys_devices_virtual_powercap.c b/collectors/debugfs.plugin/sys_devices_virtual_powercap.c
new file mode 100644
index 000000000..5f22b19e2
--- /dev/null
+++ b/collectors/debugfs.plugin/sys_devices_virtual_powercap.c
@@ -0,0 +1,217 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "debugfs_plugin.h"
+
+struct zone_t {
+ char *zone_chart_id;
+ char *subzone_chart_id;
+ char *name;
+ char *path;
+
+ unsigned long long max_energy_range_uj;
+ unsigned long long energy_uj;
+
+ struct zone_t *subzones;
+
+ struct zone_t *prev, *next;
+};
+
+static struct zone_t *rapl_zones = NULL;
+
+static bool get_measurement(const char *path, unsigned long long *energy_uj) {
+ return read_single_number_file(path, energy_uj) == 0;
+}
+
+static struct zone_t *get_rapl_zone(const char *control_type __maybe_unused, struct zone_t *parent __maybe_unused, const char *dirname) {
+ char temp[FILENAME_MAX + 1];
+ snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "name");
+
+ char name[FILENAME_MAX + 1] = "";
+ if (read_file(temp, name, sizeof(name) - 1) != 0)
+ return NULL;
+
+ char *trimmed = trim(name);
+ if (unlikely(trimmed == NULL || trimmed[0] == 0))
+ return NULL;
+
+ snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "max_energy_range_uj");
+ unsigned long long max_energy_range_uj = 0;
+ if (unlikely(read_single_number_file(temp, &max_energy_range_uj) != 0)) {
+ collector_error("Cannot read %s", temp);
+ return NULL;
+ }
+
+ snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "energy_uj");
+ unsigned long long energy_uj;
+ if (unlikely(!get_measurement(temp, &energy_uj))) {
+ collector_info("%s: Cannot read %s", trimmed, temp);
+ return NULL;
+ }
+
+ struct zone_t *zone = callocz(1, sizeof(*zone));
+
+ zone->name = strdupz(trimmed);
+ zone->path = strdupz(temp);
+
+ zone->max_energy_range_uj = max_energy_range_uj;
+ zone->energy_uj = energy_uj;
+
+ collector_info("Found zone: \"%s\"", zone->name);
+
+ return zone;
+}
+
+static struct zone_t *look_for_rapl_zones(const char *control_type, struct zone_t *parent, const char *path, int depth) {
+ if(depth > 2)
+ return NULL;
+
+ struct zone_t *base = NULL;
+
+ DIR *dir = opendir(path);
+ if (unlikely(dir == NULL))
+ return NULL;
+
+ struct dirent *de = NULL;
+ while ((de = readdir(dir))) {
+ if (de->d_type != DT_DIR || de->d_name[0] == '.')
+ continue;
+
+ if(strncmp(de->d_name, "intel-rapl:", 11) != 0)
+ continue;
+
+ char zone_path[FILENAME_MAX + 1];
+ snprintfz(zone_path, FILENAME_MAX, "%s/%s", path, de->d_name);
+
+ struct zone_t *zone = get_rapl_zone(control_type, parent, zone_path);
+ if(zone) {
+ DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(base, zone, prev, next);
+
+ if(!parent)
+ zone->subzones = look_for_rapl_zones(control_type, zone, zone_path, depth + 1);
+ }
+ }
+
+ closedir(dir);
+ return base;
+}
+
+static struct zone_t *get_main_rapl_zones(void) {
+ struct zone_t *base = NULL;
+
+ char dirname[FILENAME_MAX + 1];
+ snprintfz(dirname, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/powercap");
+
+ DIR *dir = opendir(dirname);
+ if (unlikely(dir == NULL))
+ return 0;
+
+ struct dirent *de = NULL;
+ while ((de = readdir(dir))) {
+ if (de->d_type != DT_DIR || de->d_name[0] == '.')
+ continue;
+
+ if(strncmp(de->d_name, "intel-rapl", 10) != 0)
+ continue;
+
+ char control_type_path[FILENAME_MAX + 1];
+ snprintfz(control_type_path, FILENAME_MAX, "%s/%s", dirname, de->d_name);
+
+ collector_info("Looking at control type \"%s\"", de->d_name);
+ struct zone_t *zone = look_for_rapl_zones(de->d_name, NULL, control_type_path, 0);
+ if(zone)
+ DOUBLE_LINKED_LIST_APPEND_LIST_UNSAFE(base, zone, prev, next);
+ }
+ closedir(dir);
+
+ return base;
+}
+
+int do_sys_devices_virtual_powercap(int update_every, const char *name __maybe_unused) {
+
+ if (unlikely(!rapl_zones)) {
+ rapl_zones = get_main_rapl_zones();
+ if (unlikely(!rapl_zones)) {
+ collector_info("Failed to find powercap zones.");
+ return 1;
+ }
+ }
+
+ for(struct zone_t *zone = rapl_zones; zone ; zone = zone->next) {
+ if(!zone->zone_chart_id) {
+ char id[1000 + 1];
+ snprintf(id, 1000, "cpu.powercap_intel_rapl_zone_%s", zone->name);
+ zone->zone_chart_id = strdupz(id);
+
+ fprintf(stdout,
+ "CHART '%s' '' 'Intel RAPL Zone Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
+ zone->zone_chart_id,
+ "cpu.powercap_intel_rapl_zone",
+ debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
+ NETDATA_CHART_PRIO_POWERCAP,
+ update_every);
+
+ fprintf(stdout,
+ "CLABEL 'zone' '%s' 0\n"
+ "CLABEL_COMMIT\n",
+ zone->name);
+
+ fprintf(stdout,
+ "DIMENSION 'power' '' %s 1 1000000 ''\n",
+ debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
+
+ // for the sub-zones
+ snprintf(id, 1000, "cpu.powercap_intel_rapl_subzones_%s", zone->name);
+ zone->subzone_chart_id = strdupz(id);
+ fprintf(stdout,
+ "CHART '%s' '' 'Intel RAPL Subzones Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
+ zone->subzone_chart_id,
+ "cpu.powercap_intel_rapl_subzones",
+ debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
+ NETDATA_CHART_PRIO_POWERCAP + 1,
+ update_every);
+
+ fprintf(stdout,
+ "CLABEL 'zone' '%s' 0\n"
+ "CLABEL_COMMIT\n",
+ zone->name);
+
+ for(struct zone_t *subzone = zone->subzones; subzone ; subzone = subzone->next) {
+ fprintf(stdout,
+ "DIMENSION '%s' '' %s 1 1000000 ''\n",
+ subzone->name,
+ debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
+ }
+ }
+
+ if(get_measurement(zone->path, &zone->energy_uj)) {
+ fprintf(stdout,
+ "BEGIN '%s'\n"
+ "SET power = %lld\n"
+ "END\n"
+ , zone->zone_chart_id
+ , zone->energy_uj);
+ }
+
+ if(zone->subzones) {
+ fprintf(stdout,
+ "BEGIN '%s'\n",
+ zone->subzone_chart_id);
+
+ for (struct zone_t *subzone = zone->subzones; subzone; subzone = subzone->next) {
+ if(get_measurement(subzone->path, &subzone->energy_uj)) {
+ fprintf(stdout,
+ "SET '%s' = %lld\n",
+ subzone->name,
+ subzone->energy_uj);
+ }
+ }
+
+ fprintf(stdout, "END\n");
+ }
+
+ }
+
+ fflush(stdout);
+
+ return 0;
+}