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
}