@cryptotaxi247 / netdata-1 / commits / b27de0e1c

added CPU core and package thermal throttling support; moved cpufreq to internal netdata plugin

Costa Tsaousis (ktsaou) committed Sep 9, 2017 at 17:31 UTC b27de0e1cff30219deacae6dd913bba9965faf73
1 file changed +223 -9
src/proc_stat.c
+223 -9
@@ -1,6 +1,21 @@
1 #include "common.h"
2
3 +struct per_core_single_number_file {
4 + char found:1;
5 + const char *filename;
6 + int fd;
7 + collected_number value;
8 + RRDDIM *rd;
9 +};
10 +
11 +#define CORE_THROTTLE_COUNT_INDEX 0
12 +#define PACKAGE_THROTTLE_COUNT_INDEX 1
13 +#define SCALING_CUR_FREQ_INDEX 2
14 +#define PER_CORE_FILES 3
15 +
16 struct cpu_chart {
17 + const char *id;
18 +
19 RRDSET *st;
20 RRDDIM *rd_user;
21 RRDDIM *rd_nice;
@@ -13,30 +28,113 @@ struct cpu_chart {
28 RRDDIM *rd_guest;
29 RRDDIM *rd_guest_nice;
30
31 + struct per_core_single_number_file files[PER_CORE_FILES];
32 };
33
34 +
35 +static int read_per_core_files(struct cpu_chart *all_cpu_charts, size_t len, size_t index) {
36 + char buf[50 + 1];
37 + size_t x, files_read = 0, files_nonzero = 0;
38 +
39 + for(x = 0; x < len ; x++) {
40 + struct per_core_single_number_file *f = &all_cpu_charts[x].files[index];
41 +
42 + f->found = 0;
43 +
44 + if(unlikely(!f->filename))
45 + continue;
46 +
47 + if(unlikely(f->fd == -1)) {
48 + f->fd = open(f->filename, O_RDONLY);
49 + if (unlikely(f->fd == -1))
50 + error("Cannot open file '%s'", f->filename);
51 + continue;
52 + }
53 +
54 + ssize_t ret = read(f->fd, buf, 50);
55 + if(unlikely(ret == -1)) {
56 + error("Cannot read file '%s'", f->filename);
57 + close(f->fd);
58 + f->fd = -1;
59 + continue;
60 + }
61 + buf[ret] = '\0';
62 +
63 + if(lseek(f->fd, 0, SEEK_SET) == -1) {
64 + error("Cannot seek in file '%s'", f->filename);
65 + close(f->fd);
66 + f->fd = -1;
67 + }
68 +
69 + files_read++;
70 + f->found = 1;
71 +
72 + f->value = str2ll(buf, NULL);
73 + // info("read '%s', parsed as " COLLECTED_NUMBER_FORMAT, buf, f->value);
74 + if(likely(f->value != 0))
75 + files_nonzero++;
76 + }
77 +
78 + if(files_read == 0)
79 + return -1;
80 +
81 + if(files_nonzero == 0)
82 + return 0;
83 +
84 + return (int)files_nonzero;
85 +}
86 +
87 +static void chart_per_core_files(struct cpu_chart *all_cpu_charts, size_t len, size_t index, RRDSET *st, collected_number multiplier, collected_number divisor, RRD_ALGORITHM algorithm) {
88 + size_t x;
89 + for(x = 0; x < len ; x++) {
90 + struct per_core_single_number_file *f = &all_cpu_charts[x].files[index];
91 +
92 + if(unlikely(!f->found))
93 + continue;
94 +
95 + if(unlikely(!f->rd))
96 + f->rd = rrddim_add(st, all_cpu_charts[x].id, NULL, multiplier, divisor, algorithm);
97 +
98 + rrddim_set_by_pointer(st, f->rd, f->value);
99 + }
100 +}
101 +
102 int do_proc_stat(int update_every, usec_t dt) {
103 (void)dt;
104
105 static struct cpu_chart *all_cpu_charts = NULL;
106 static size_t all_cpu_charts_size = 0;
107 static procfile *ff = NULL;
24 - static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
108 + static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1, do_core_throttle_count = -1, do_package_throttle_count = -1, do_scaling_cur_freq = -1;
109 static uint32_t hash_intr, hash_ctxt, hash_processes, hash_procs_running, hash_procs_blocked;
110 + static char *core_throttle_count_filename = NULL, *package_throttle_count_filename = NULL, *scaling_cur_freq_filename = NULL;
111
112 if(unlikely(do_cpu == -1)) {
28 - do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
29 - do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
30 - do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
31 - do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
32 - do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
33 - do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
113 + do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
114 + do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
115 + do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
116 + do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
117 + do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
118 + do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
119 + do_core_throttle_count = config_get_boolean_ondemand("plugin:proc:/proc/stat", "core_throttle_count", CONFIG_BOOLEAN_AUTO);
120 + do_package_throttle_count = config_get_boolean_ondemand("plugin:proc:/proc/stat", "package_throttle_count", CONFIG_BOOLEAN_AUTO);
121 + do_scaling_cur_freq = config_get_boolean_ondemand("plugin:proc:/proc/stat", "scaling_cur_freq", CONFIG_BOOLEAN_AUTO);
122
123 hash_intr = simple_hash("intr");
124 hash_ctxt = simple_hash("ctxt");
125 hash_processes = simple_hash("processes");
126 hash_procs_running = simple_hash("procs_running");
127 hash_procs_blocked = simple_hash("procs_blocked");
128 +
129 + char filename[FILENAME_MAX + 1];
130 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/thermal_throttle/core_throttle_count");
131 + core_throttle_count_filename = config_get("plugin:proc:/proc/stat", "core_throttle_count filename to monitor", filename);
132 +
133 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/thermal_throttle/package_throttle_count");
134 + package_throttle_count_filename = config_get("plugin:proc:/proc/stat", "package_throttle_count filename to monitor", filename);
135 +
136 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/cpu/%s/cpufreq/scaling_cur_freq");
137 + scaling_cur_freq_filename = config_get("plugin:proc:/proc/stat", "scaling_cur_freq filename to monitor", filename);
138 }
139
140 if(unlikely(!ff)) {
@@ -100,6 +198,8 @@ int do_proc_stat(int update_every, usec_t dt) {
198 struct cpu_chart *cpu_chart = &all_cpu_charts[core];
199
200 if(unlikely(!cpu_chart->st)) {
201 + cpu_chart->id = strdupz(id);
202 +
203 if(core == 0) {
204 title = "Total CPU utilization";
205 type = "system";
@@ -116,8 +216,36 @@ int do_proc_stat(int update_every, usec_t dt) {
216
217 // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
218 // FIXME: check for /sys/devices/system/cpu/cpu*/cpufreq/stats/time_in_state
119 - // FIXME: check for /sys/devices/system/cpu/cpu*/thermal_throttle/core_throttle_count
120 - // FIXME: check for /sys/devices/system/cpu/cpu*/thermal_throttle/package_throttle_count
219 +
220 + char filename[FILENAME_MAX + 1];
221 + struct stat stbuf;
222 +
223 + if(do_core_throttle_count != CONFIG_BOOLEAN_NO) {
224 + snprintfz(filename, FILENAME_MAX, core_throttle_count_filename, id);
225 + if (stat(filename, &stbuf) == 0) {
226 + cpu_chart->files[CORE_THROTTLE_COUNT_INDEX].filename = strdupz(filename);
227 + cpu_chart->files[CORE_THROTTLE_COUNT_INDEX].fd = -1;
228 + do_core_throttle_count = CONFIG_BOOLEAN_YES;
229 + }
230 + }
231 +
232 + if(do_package_throttle_count != CONFIG_BOOLEAN_NO) {
233 + snprintfz(filename, FILENAME_MAX, package_throttle_count_filename, id);
234 + if (stat(filename, &stbuf) == 0) {
235 + cpu_chart->files[PACKAGE_THROTTLE_COUNT_INDEX].filename = strdupz(filename);
236 + cpu_chart->files[PACKAGE_THROTTLE_COUNT_INDEX].fd = -1;
237 + do_package_throttle_count = CONFIG_BOOLEAN_YES;
238 + }
239 + }
240 +
241 + if(do_scaling_cur_freq != CONFIG_BOOLEAN_NO) {
242 + snprintfz(filename, FILENAME_MAX, scaling_cur_freq_filename, id);
243 + if (stat(filename, &stbuf) == 0) {
244 + cpu_chart->files[SCALING_CUR_FREQ_INDEX].filename = strdupz(filename);
245 + cpu_chart->files[SCALING_CUR_FREQ_INDEX].fd = -1;
246 + do_scaling_cur_freq = CONFIG_BOOLEAN_YES;
247 + }
248 + }
249 }
250
251 cpu_chart->st = rrdset_create_localhost(type, id, NULL, family, context, title, "percentage", priority, update_every, RRDSET_TYPE_STACKED);
@@ -240,5 +368,91 @@ int do_proc_stat(int update_every, usec_t dt) {
368 rrdset_done(st_processes);
369 }
370
371 + if(likely(all_cpu_charts_size > 1)) {
372 + if(likely(do_core_throttle_count != CONFIG_BOOLEAN_NO)) {
373 + int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, CORE_THROTTLE_COUNT_INDEX);
374 + if(likely(r != -1 && (do_core_throttle_count == CONFIG_BOOLEAN_YES || r > 0))) {
375 + do_core_throttle_count = CONFIG_BOOLEAN_YES;
376 +
377 + static RRDSET *st_core_throttle_count = NULL;
378 +
379 + if (unlikely(!st_core_throttle_count))
380 + st_core_throttle_count = rrdset_create_localhost(
381 + "cpu"
382 + , "core_throttling"
383 + , NULL
384 + , "throttling"
385 + , "cpu.core_throttling"
386 + , "Core Thermal Throttling Events"
387 + , "events/s"
388 + , 5001
389 + , update_every
390 + , RRDSET_TYPE_LINE
391 + );
392 + else
393 + rrdset_next(st_core_throttle_count);
394 +
395 + chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, CORE_THROTTLE_COUNT_INDEX, st_core_throttle_count, 1, 1, RRD_ALGORITHM_INCREMENTAL);
396 + rrdset_done(st_core_throttle_count);
397 + }
398 + }
399 +
400 + if(likely(do_package_throttle_count != CONFIG_BOOLEAN_NO)) {
401 + int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, PACKAGE_THROTTLE_COUNT_INDEX);
402 + if(likely(r != -1 && (do_package_throttle_count == CONFIG_BOOLEAN_YES || r > 0))) {
403 + do_package_throttle_count = CONFIG_BOOLEAN_YES;
404 +
405 + static RRDSET *st_package_throttle_count = NULL;
406 +
407 + if(unlikely(!st_package_throttle_count))
408 + st_package_throttle_count = rrdset_create_localhost(
409 + "cpu"
410 + , "package_throttling"
411 + , NULL
412 + , "throttling"
413 + , "cpu.package_throttling"
414 + , "Package Thermal Throttling Events"
415 + , "events/s"
416 + , 5002
417 + , update_every
418 + , RRDSET_TYPE_LINE
419 + );
420 + else
421 + rrdset_next(st_package_throttle_count);
422 +
423 + chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, PACKAGE_THROTTLE_COUNT_INDEX, st_package_throttle_count, 1, 1, RRD_ALGORITHM_INCREMENTAL);
424 + rrdset_done(st_package_throttle_count);
425 + }
426 + }
427 +
428 + if(likely(do_scaling_cur_freq != CONFIG_BOOLEAN_NO)) {
429 + int r = read_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, SCALING_CUR_FREQ_INDEX);
430 + if(likely(r != -1 && (do_scaling_cur_freq == CONFIG_BOOLEAN_YES || r > 0))) {
431 + do_scaling_cur_freq = CONFIG_BOOLEAN_YES;
432 +
433 + static RRDSET *st_scaling_cur_freq = NULL;
434 +
435 + if(unlikely(!st_scaling_cur_freq))
436 + st_scaling_cur_freq = rrdset_create_localhost(
437 + "cpu"
438 + , "scaling_cur_freq"
439 + , NULL
440 + , "cpufreq"
441 + , "cpu.scaling_cur_freq"
442 + , "Per CPU Core, Current CPU Scaling Frequency"
443 + , "MHz"
444 + , 5003
445 + , update_every
446 + , RRDSET_TYPE_LINE
447 + );
448 + else
449 + rrdset_next(st_scaling_cur_freq);
450 +
451 + chart_per_core_files(&all_cpu_charts[1], all_cpu_charts_size - 1, SCALING_CUR_FREQ_INDEX, st_scaling_cur_freq, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
452 + rrdset_done(st_scaling_cur_freq);
453 + }
454 + }
455 + }
456 +
457 return 0;
458 }