]> arthur.barton.de Git - netdata.git/blob - src/sys_devices_system_edac_mc.c
Merge pull request #1998 from ktsaou/master
[netdata.git] / src / sys_devices_system_edac_mc.c
1 #include "common.h"
2
3 struct mc {
4     char *name;
5     char ce_updated;
6     char ue_updated;
7
8     char *ce_count_filename;
9     char *ue_count_filename;
10
11     procfile *ce_ff;
12     procfile *ue_ff;
13
14     collected_number ce_count;
15     collected_number ue_count;
16
17     RRDDIM *ce_rd;
18     RRDDIM *ue_rd;
19
20     struct mc *next;
21 };
22 static struct mc *mc_root = NULL;
23
24 static void find_all_mc() {
25     char name[FILENAME_MAX + 1];
26     snprintfz(name, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/system/edac/mc");
27     char *dirname = config_get("plugin:proc:/sys/devices/system/edac/mc", "directory to monitor", name);
28
29     DIR *dir = opendir(dirname);
30     if(!dir) {
31         error("Cannot read ECC memory errors directory '%s'", dirname);
32         return;
33     }
34
35     struct dirent *de = NULL;
36     while((de = readdir(dir))) {
37         if(de->d_type == DT_DIR && de->d_name[0] == 'm' && de->d_name[1] == 'c' && isdigit(de->d_name[2])) {
38             struct mc *m = callocz(1, sizeof(struct mc));
39             m->name = strdupz(de->d_name);
40
41             struct stat st;
42
43             snprintfz(name, FILENAME_MAX, "%s/%s/ce_count", dirname, de->d_name);
44             if(stat(name, &st) != -1)
45                 m->ce_count_filename = strdupz(name);
46
47             snprintfz(name, FILENAME_MAX, "%s/%s/ue_count", dirname, de->d_name);
48             if(stat(name, &st) != -1)
49                 m->ue_count_filename = strdupz(name);
50
51             if(!m->ce_count_filename && !m->ue_count_filename) {
52                 freez(m->name);
53                 freez(m);
54             }
55             else {
56                 m->next = mc_root;
57                 mc_root = m;
58             }
59         }
60     }
61
62     closedir(dir);
63 }
64
65 int do_proc_sys_devices_system_edac_mc(int update_every, usec_t dt) {
66     (void)dt;
67
68     if(unlikely(mc_root == NULL)) {
69         find_all_mc();
70         if(unlikely(mc_root == NULL))
71             return 1;
72     }
73
74     static int do_ce = -1, do_ue = -1;
75     calculated_number ce_sum = 0, ue_sum = 0;
76     struct mc *m;
77
78     if(unlikely(do_ce == -1)) {
79         do_ce = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory correctable errors", CONFIG_BOOLEAN_AUTO);
80         do_ue = config_get_boolean_ondemand("plugin:proc:/sys/devices/system/edac/mc", "enable ECC memory uncorrectable errors", CONFIG_BOOLEAN_AUTO);
81     }
82
83     if(do_ce != CONFIG_BOOLEAN_NO) {
84         for(m = mc_root; m; m = m->next) {
85             if(m->ce_count_filename) {
86                 m->ce_updated = 0;
87
88                 if(unlikely(!m->ce_ff)) {
89                     m->ce_ff = procfile_open(m->ce_count_filename, " \t", PROCFILE_FLAG_DEFAULT);
90                     if(unlikely(!m->ce_ff))
91                         continue;
92                 }
93
94                 m->ce_ff = procfile_readall(m->ce_ff);
95                 if(unlikely(!m->ce_ff || procfile_lines(m->ce_ff) < 1 || procfile_linewords(m->ce_ff, 0) < 1))
96                     continue;
97
98                 m->ce_count = str2ull(procfile_lineword(m->ce_ff, 0, 0));
99                 ce_sum += m->ce_count;
100                 m->ce_updated = 1;
101             }
102         }
103     }
104
105     if(do_ue != CONFIG_BOOLEAN_NO) {
106         for(m = mc_root; m; m = m->next) {
107             if(m->ue_count_filename) {
108                 m->ue_updated = 0;
109
110                 if(unlikely(!m->ue_ff)) {
111                     m->ue_ff = procfile_open(m->ue_count_filename, " \t", PROCFILE_FLAG_DEFAULT);
112                     if(unlikely(!m->ue_ff))
113                         continue;
114                 }
115
116                 m->ue_ff = procfile_readall(m->ue_ff);
117                 if(unlikely(!m->ue_ff || procfile_lines(m->ue_ff) < 1 || procfile_linewords(m->ue_ff, 0) < 1))
118                     continue;
119
120                 m->ue_count = str2ull(procfile_lineword(m->ue_ff, 0, 0));
121                 ue_sum += m->ue_count;
122                 m->ue_updated = 1;
123             }
124         }
125     }
126
127     // --------------------------------------------------------------------
128
129     if(do_ce == CONFIG_BOOLEAN_YES || (do_ce == CONFIG_BOOLEAN_AUTO && ce_sum > 0)) {
130         do_ce = CONFIG_BOOLEAN_YES;
131
132         static RRDSET *ce_st = NULL;
133
134         if(unlikely(!ce_st)) {
135             ce_st = rrdset_find_localhost("mem.ecc_ce");
136             if(unlikely(!ce_st))
137                 ce_st = rrdset_create_localhost("mem", "ecc_ce", NULL, "ecc", NULL, "ECC Memory Correctable Errors"
138                                                 , "errors", 6600, update_every, RRDSET_TYPE_LINE);
139
140             for(m = mc_root; m; m = m->next)
141                 if(m->ce_count_filename)
142                     m->ce_rd = rrddim_add(ce_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
143         }
144         else
145             rrdset_next(ce_st);
146
147         for(m = mc_root; m; m = m->next)
148             if(m->ce_count_filename && m->ce_updated)
149                 rrddim_set_by_pointer(ce_st, m->ce_rd, m->ce_count);
150
151         rrdset_done(ce_st);
152     }
153
154     // --------------------------------------------------------------------
155
156     if(do_ue == CONFIG_BOOLEAN_YES || (do_ue == CONFIG_BOOLEAN_AUTO && ue_sum > 0)) {
157         do_ue = CONFIG_BOOLEAN_YES;
158
159         static RRDSET *ue_st = NULL;
160
161         if(unlikely(!ue_st)) {
162             ue_st = rrdset_find_localhost("mem.ecc_ue");
163
164             if(unlikely(!ue_st))
165                 ue_st = rrdset_create_localhost("mem", "ecc_ue", NULL, "ecc", NULL, "ECC Memory Uncorrectable Errors"
166                                                 , "errors", 6610, update_every, RRDSET_TYPE_LINE);
167
168             for(m = mc_root; m; m = m->next)
169                 if(m->ue_count_filename)
170                     m->ue_rd = rrddim_add(ue_st, m->name, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
171         }
172         else
173             rrdset_next(ue_st);
174
175         for(m = mc_root; m; m = m->next)
176             if(m->ue_count_filename && m->ue_updated)
177                 rrddim_set_by_pointer(ue_st, m->ue_rd, m->ue_count);
178
179         rrdset_done(ue_st);
180     }
181
182     return 0;
183 }