]> arthur.barton.de Git - netdata.git/blob - src/sys_devices_system_node.c
449bbf0ded7e39ae8bf30baee0717a4ade000fa1
[netdata.git] / src / sys_devices_system_node.c
1 #include "common.h"
2
3 struct node {
4     char *name;
5     char *numastat_filename;
6     procfile *numastat_ff;
7     RRDSET *numastat_st;
8     struct node *next;
9 };
10 static struct node *numa_root = NULL;
11
12 static int find_all_nodes() {
13     int numa_node_count = 0;
14     char name[FILENAME_MAX + 1];
15     snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/node");
16     char *dirname = config_get("plugin:proc:/sys/devices/system/node", "directory to monitor", name);
17
18     DIR *dir = opendir(dirname);
19     if(!dir) {
20         error("Cannot read NUMA node directory '%s'", dirname);
21         return 0;
22     }
23
24     struct dirent *de = NULL;
25     while((de = readdir(dir))) {
26         if(de->d_type != DT_DIR)
27             continue;
28
29         if(strncmp(de->d_name, "node", 4) != 0)
30             continue;
31
32         if(!isdigit(de->d_name[4]))
33             continue;
34
35         numa_node_count++;
36
37         struct node *m = callocz(1, sizeof(struct node));
38         m->name = strdupz(de->d_name);
39
40         struct stat st;
41
42         snprintfz(name, FILENAME_MAX, "%s/%s/numastat", dirname, de->d_name);
43         if(stat(name, &st) == -1) {
44             freez(m->name);
45             freez(m);
46             continue;
47         }
48
49         m->numastat_filename = strdupz(name);
50
51         m->next = numa_root;
52         numa_root = m;
53     }
54
55     closedir(dir);
56
57     return numa_node_count;
58 }
59
60 int do_proc_sys_devices_system_node(int update_every, usec_t dt) {
61     (void)dt;
62
63     static int numa_node_count = 0;
64
65     if(unlikely(numa_root == NULL)) {
66         numa_node_count = find_all_nodes(update_every);
67         if(unlikely(numa_root == NULL))
68             return 1;
69     }
70
71     static int do_numastat = -1;
72     struct node *m;
73
74     if(unlikely(do_numastat == -1)) {
75         do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_BOOLEAN_AUTO);
76     }
77
78     if(do_numastat == CONFIG_BOOLEAN_YES || (do_numastat == CONFIG_BOOLEAN_AUTO && numa_node_count >= 2)) {
79         for(m = numa_root; m; m = m->next) {
80             if(m->numastat_filename) {
81                 if(unlikely(!m->numastat_ff)) {
82                     m->numastat_ff = procfile_open(m->numastat_filename, " ", PROCFILE_FLAG_DEFAULT);
83                     if(unlikely(!m->numastat_ff))
84                         continue;
85                 }
86
87                 m->numastat_ff = procfile_readall(m->numastat_ff);
88                 if(unlikely(!m->numastat_ff || procfile_lines(m->numastat_ff) < 1 || procfile_linewords(m->numastat_ff, 0) < 1))
89                     continue;
90
91                 procfile *ff = m->numastat_ff;
92
93                 RRDSET *st = m->numastat_st;
94                 if(unlikely(!st)) {
95                     st = rrdset_create_localhost("mem", m->name, NULL, "numa", NULL, "NUMA events", "events/s", 1000
96                                                  , update_every, RRDSET_TYPE_LINE);
97                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
98
99                     rrddim_add(st, "local_node", "local", 1, 1, RRD_ALGORITHM_INCREMENTAL);
100                     rrddim_add(st, "numa_foreign", "foreign", 1, 1, RRD_ALGORITHM_INCREMENTAL);
101                     rrddim_add(st, "interleave_hit", "interleave", 1, 1, RRD_ALGORITHM_INCREMENTAL);
102                     rrddim_add(st, "other_node", "other", 1, 1, RRD_ALGORITHM_INCREMENTAL);
103
104                     m->numastat_st = st;
105                 }
106                 else rrdset_next(st);
107
108                 uint32_t lines = procfile_lines(ff), l;
109                 for(l = 0; l < lines; l++) {
110                     uint32_t words = procfile_linewords(ff, l);
111                     if(unlikely(words < 2)) {
112                         if(unlikely(words)) error("Cannot read %s numastat line %u. Expected 2 params, read %u.", m->name, l, words);
113                         continue;
114                     }
115
116                     char *name = procfile_lineword(ff, l, 0);
117                     char *value = procfile_lineword(ff, l, 1);
118                     if (unlikely(!name || !*name || !value || !*value)) continue;
119
120                     rrddim_set(st, name, strtoull(value, NULL, 10));
121                 }
122                 rrdset_done(st);
123             }
124         }
125     }
126
127     return 0;
128 }