]> arthur.barton.de Git - netdata.git/blob - src/sys_devices_system_node.c
Merge pull request #1998 from ktsaou/master
[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 uint32_t hash_local_node = 0, hash_numa_foreign = 0, hash_interleave_hit = 0, hash_other_node = 0, hash_numa_hit = 0, hash_numa_miss = 0;
64     static int do_numastat = -1, numa_node_count = 0;
65     struct node *m;
66
67     if(unlikely(numa_root == NULL)) {
68         numa_node_count = find_all_nodes();
69         if(unlikely(numa_root == NULL))
70             return 1;
71     }
72
73     if(unlikely(do_numastat == -1)) {
74         do_numastat = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/node", "enable per-node numa metrics", CONFIG_BOOLEAN_AUTO);
75
76         hash_local_node     = simple_hash("local_node");
77         hash_numa_foreign   = simple_hash("numa_foreign");
78         hash_interleave_hit = simple_hash("interleave_hit");
79         hash_other_node     = simple_hash("other_node");
80         hash_numa_hit       = simple_hash("numa_hit");
81         hash_numa_miss      = simple_hash("numa_miss");
82     }
83
84     if(do_numastat == CONFIG_BOOLEAN_YES || (do_numastat == CONFIG_BOOLEAN_AUTO && numa_node_count >= 2)) {
85         for(m = numa_root; m; m = m->next) {
86             if(m->numastat_filename) {
87
88                 if(unlikely(!m->numastat_ff)) {
89                     m->numastat_ff = procfile_open(m->numastat_filename, " ", PROCFILE_FLAG_DEFAULT);
90
91                     if(unlikely(!m->numastat_ff))
92                         continue;
93                 }
94
95                 m->numastat_ff = procfile_readall(m->numastat_ff);
96                 if(unlikely(!m->numastat_ff || procfile_lines(m->numastat_ff) < 1 || procfile_linewords(m->numastat_ff, 0) < 1))
97                     continue;
98
99                 if(unlikely(!m->numastat_st)) {
100                     m->numastat_st = rrdset_create_localhost(
101                             "mem"
102                             , m->name
103                             , NULL
104                             , "numa"
105                             , NULL
106                             , "NUMA events"
107                             , "events/s"
108                             , 1000
109                             , update_every
110                             , RRDSET_TYPE_LINE
111                     );
112
113                     rrdset_flag_set(m->numastat_st, RRDSET_FLAG_DETAIL);
114
115                     rrddim_add(m->numastat_st, "numa_hit",       "hit",        1, 1, RRD_ALGORITHM_INCREMENTAL);
116                     rrddim_add(m->numastat_st, "numa_miss",      "miss",       1, 1, RRD_ALGORITHM_INCREMENTAL);
117                     rrddim_add(m->numastat_st, "local_node",     "local",      1, 1, RRD_ALGORITHM_INCREMENTAL);
118                     rrddim_add(m->numastat_st, "numa_foreign",   "foreign",    1, 1, RRD_ALGORITHM_INCREMENTAL);
119                     rrddim_add(m->numastat_st, "interleave_hit", "interleave", 1, 1, RRD_ALGORITHM_INCREMENTAL);
120                     rrddim_add(m->numastat_st, "other_node",     "other",      1, 1, RRD_ALGORITHM_INCREMENTAL);
121
122                 }
123                 else rrdset_next(m->numastat_st);
124
125                 size_t lines = procfile_lines(m->numastat_ff), l;
126                 for(l = 0; l < lines; l++) {
127                     size_t words = procfile_linewords(m->numastat_ff, l);
128
129                     if(unlikely(words < 2)) {
130                         if(unlikely(words))
131                             error("Cannot read %s numastat line %zu. Expected 2 params, read %zu.", m->name, l, words);
132                         continue;
133                     }
134
135                     char *name  = procfile_lineword(m->numastat_ff, l, 0);
136                     char *value = procfile_lineword(m->numastat_ff, l, 1);
137
138                     if (unlikely(!name || !*name || !value || !*value))
139                         continue;
140
141                     uint32_t hash = simple_hash(name);
142                     if(likely(
143                                (hash == hash_numa_hit       && !strcmp(name, "numa_hit"))
144                             || (hash == hash_numa_miss      && !strcmp(name, "numa_miss"))
145                             || (hash == hash_local_node     && !strcmp(name, "local_node"))
146                             || (hash == hash_numa_foreign   && !strcmp(name, "numa_foreign"))
147                             || (hash == hash_interleave_hit && !strcmp(name, "interleave_hit"))
148                             || (hash == hash_other_node     && !strcmp(name, "other_node"))
149                     ))
150                         rrddim_set(m->numastat_st, name, (collected_number)str2kernel_uint_t(value));
151                 }
152
153                 rrdset_done(m->numastat_st);
154             }
155         }
156     }
157
158     return 0;
159 }