master
c 211 lines 6.84 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "debugfs_plugin.h"
4
5 struct zone_t {
6 char *zone_chart_id;
7 char *subzone_chart_id;
8 char *name;
9 char *path;
10
11 unsigned long long max_energy_range_uj;
12 unsigned long long energy_uj;
13
14 struct zone_t *subzones;
15
16 struct zone_t *prev, *next;
17 };
18
19 static struct zone_t *rapl_zones = NULL;
20
21 static bool get_measurement(const char *path, unsigned long long *energy_uj) {
22 return read_single_number_file(path, energy_uj) == 0;
23 }
24
25 static struct zone_t *get_rapl_zone(const char *control_type __maybe_unused, struct zone_t *parent __maybe_unused, const char *dirname) {
26 char temp[FILENAME_MAX + 1];
27 snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "name");
28
29 char name[FILENAME_MAX + 1] = "";
30 if (read_txt_file(temp, name, sizeof(name)) != 0)
31 return NULL;
32
33 char *trimmed = trim(name);
34 if (unlikely(trimmed == NULL || trimmed[0] == 0))
35 return NULL;
36
37 snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "max_energy_range_uj");
38 unsigned long long max_energy_range_uj = 0;
39 if (unlikely(read_single_number_file(temp, &max_energy_range_uj) != 0)) {
40 collector_error("Cannot read %s", temp);
41 return NULL;
42 }
43
44 snprintfz(temp, FILENAME_MAX, "%s/%s", dirname, "energy_uj");
45 unsigned long long energy_uj;
46 if (unlikely(!get_measurement(temp, &energy_uj))) {
47 collector_info("%s: Cannot read %s", trimmed, temp);
48 return NULL;
49 }
50
51 struct zone_t *zone = callocz(1, sizeof(*zone));
52
53 zone->name = strdupz(trimmed);
54 zone->path = strdupz(temp);
55
56 zone->max_energy_range_uj = max_energy_range_uj;
57 zone->energy_uj = energy_uj;
58
59 collector_info("Found zone: \"%s\"", zone->name);
60
61 return zone;
62 }
63
64 static struct zone_t *look_for_rapl_zones(const char *control_type, struct zone_t *parent, const char *path, int depth) {
65 if(depth > 2)
66 return NULL;
67
68 struct zone_t *base = NULL;
69
70 DIR *dir = opendir(path);
71 if (unlikely(dir == NULL))
72 return NULL;
73
74 struct dirent *de = NULL;
75 while ((de = readdir(dir))) {
76 if (de->d_type != DT_DIR || de->d_name[0] == '.')
77 continue;
78
79 if(strncmp(de->d_name, "intel-rapl:", 11) != 0)
80 continue;
81
82 char zone_path[FILENAME_MAX + 1];
83 snprintfz(zone_path, FILENAME_MAX, "%s/%s", path, de->d_name);
84
85 struct zone_t *zone = get_rapl_zone(control_type, parent, zone_path);
86 if(zone) {
87 DOUBLE_LINKED_LIST_APPEND_ITEM_UNSAFE(base, zone, prev, next);
88
89 if(!parent)
90 zone->subzones = look_for_rapl_zones(control_type, zone, zone_path, depth + 1);
91 }
92 }
93
94 closedir(dir);
95 return base;
96 }
97
98 static struct zone_t *get_main_rapl_zones(void) {
99 struct zone_t *base = NULL;
100
101 char dirname[FILENAME_MAX + 1];
102 snprintfz(dirname, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/powercap");
103
104 DIR *dir = opendir(dirname);
105 if (unlikely(dir == NULL))
106 return 0;
107
108 struct dirent *de = NULL;
109 while ((de = readdir(dir))) {
110 if (de->d_type != DT_DIR || de->d_name[0] == '.')
111 continue;
112
113 if(strncmp(de->d_name, "intel-rapl", 10) != 0)
114 continue;
115
116 char control_type_path[FILENAME_MAX + 1];
117 snprintfz(control_type_path, FILENAME_MAX, "%s/%s", dirname, de->d_name);
118
119 collector_info("Looking at control type \"%s\"", de->d_name);
120 struct zone_t *zone = look_for_rapl_zones(de->d_name, NULL, control_type_path, 0);
121 if(zone)
122 DOUBLE_LINKED_LIST_APPEND_LIST_UNSAFE(base, zone, prev, next);
123 }
124 closedir(dir);
125
126 return base;
127 }
128
129 int do_module_devices_powercap(int update_every, const char *name __maybe_unused) {
130
131 if (unlikely(!rapl_zones)) {
132 rapl_zones = get_main_rapl_zones();
133 if (unlikely(!rapl_zones)) {
134 collector_info("Failed to find powercap zones.");
135 return 1;
136 }
137 }
138
139 netdata_mutex_lock(&stdout_mutex);
140
141 for(struct zone_t *zone = rapl_zones; zone ; zone = zone->next) {
142 if(!zone->zone_chart_id) {
143 char id[1000 + 1];
144 snprintf(id, 1000, "cpu.powercap_intel_rapl_zone_%s", zone->name);
145 zone->zone_chart_id = strdupz(id);
146
147 printf(PLUGINSD_KEYWORD_CHART " '%s' '' 'Intel RAPL Zone Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
148 zone->zone_chart_id,
149 "cpu.powercap_intel_rapl_zone",
150 debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
151 NETDATA_CHART_PRIO_POWERCAP,
152 update_every);
153
154 printf(PLUGINSD_KEYWORD_CLABEL " 'zone' '%s' 1\n"
155 PLUGINSD_KEYWORD_CLABEL_COMMIT "\n",
156 zone->name);
157
158 printf(PLUGINSD_KEYWORD_DIMENSION " 'power' '' %s 1 1000000 ''\n",
159 debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
160
161 // the sub-zones
162 snprintf(id, 1000, "cpu.powercap_intel_rapl_subzones_%s", zone->name);
163 zone->subzone_chart_id = strdupz(id);
164 printf(PLUGINSD_KEYWORD_CHART " '%s' '' 'Intel RAPL Subzones Power Consumption' 'Watts' 'powercap' '%s' '%s' %d %d '' 'debugfs.plugin' 'intel_rapl'\n",
165 zone->subzone_chart_id,
166 "cpu.powercap_intel_rapl_subzones",
167 debugfs_rrdset_type_name(RRDSET_TYPE_LINE),
168 NETDATA_CHART_PRIO_POWERCAP + 1,
169 update_every);
170
171 printf(PLUGINSD_KEYWORD_CLABEL " 'zone' '%s' 1\n"
172 PLUGINSD_KEYWORD_CLABEL_COMMIT "\n",
173 zone->name);
174
175 for(struct zone_t *subzone = zone->subzones; subzone ; subzone = subzone->next) {
176 printf(PLUGINSD_KEYWORD_DIMENSION " '%s' '' %s 1 1000000 ''\n",
177 subzone->name,
178 debugfs_rrd_algorithm_name(RRD_ALGORITHM_INCREMENTAL));
179 }
180 }
181
182 if(get_measurement(zone->path, &zone->energy_uj)) {
183 printf(PLUGINSD_KEYWORD_BEGIN " '%s'\n"
184 PLUGINSD_KEYWORD_SET " power = %llu\n"
185 PLUGINSD_KEYWORD_END "\n"
186 , zone->zone_chart_id
187 , zone->energy_uj);
188 }
189
190 if(zone->subzones) {
191 printf(PLUGINSD_KEYWORD_BEGIN " '%s'\n",
192 zone->subzone_chart_id);
193
194 for (struct zone_t *subzone = zone->subzones; subzone; subzone = subzone->next) {
195 if(get_measurement(subzone->path, &subzone->energy_uj)) {
196 printf(PLUGINSD_KEYWORD_SET " '%s' = %llu\n",
197 subzone->name,
198 subzone->energy_uj);
199 }
200 }
201
202 printf(PLUGINSD_KEYWORD_END "\n");
203 }
204
205 }
206
207 fflush(stdout);
208 netdata_mutex_unlock(&stdout_mutex);
209
210 return 0;
211 }