]> arthur.barton.de Git - netdata.git/blob - src/proc_diskstats.c
log: now is logging program name too; tc: huge optimizations; procfile: optimized...
[netdata.git] / src / proc_diskstats.c
1 #include <inttypes.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "log.h"
7 #include "config.h"
8 #include "procfile.h"
9 #include "rrd.h"
10 #include "plugin_proc.h"
11
12 #define RRD_TYPE_DISK                           "disk"
13 #define RRD_TYPE_DISK_LEN                       strlen(RRD_TYPE_DISK)
14
15 #define MAX_PROC_DISKSTATS_LINE 4096
16
17 int do_proc_diskstats(int update_every, unsigned long long dt) {
18         static procfile *ff = NULL;
19
20         static int enable_new_disks = -1;
21         static int do_io = -1, do_ops = -1, do_merged_ops = -1, do_iotime = -1, do_cur_ops = -1;
22
23         if(enable_new_disks == -1)      enable_new_disks = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", 1);
24
25         if(do_io == -1)                 do_io                   = config_get_boolean("plugin:proc:/proc/diskstats", "bandwidth for all disks", 1);
26         if(do_ops == -1)                do_ops                  = config_get_boolean("plugin:proc:/proc/diskstats", "operations for all disks", 1);
27         if(do_merged_ops == -1) do_merged_ops   = config_get_boolean("plugin:proc:/proc/diskstats", "merged operations for all disks", 1);
28         if(do_iotime == -1)             do_iotime               = config_get_boolean("plugin:proc:/proc/diskstats", "i/o time for all disks", 1);
29         if(do_cur_ops == -1)    do_cur_ops              = config_get_boolean("plugin:proc:/proc/diskstats", "current operations for all disks", 1);
30
31         if(dt) {};
32
33         if(!ff) ff = procfile_open("/proc/diskstats", " \t", PROCFILE_FLAG_DEFAULT);
34         if(!ff) return 1;
35
36         ff = procfile_readall(ff);
37         if(!ff) return 0; // we return 0, so that we will retry to open it next time
38
39         uint32_t lines = procfile_lines(ff), l;
40         uint32_t words;
41
42         for(l = 0; l < lines ;l++) {
43                 char *disk;
44                 unsigned long long      major = 0, minor = 0,
45                                                         reads = 0,  reads_merged = 0,  readsectors = 0,  readms = 0,
46                                                         writes = 0, writes_merged = 0, writesectors = 0, writems = 0,
47                                                         currentios = 0, iosms = 0, wiosms = 0;
48
49                 words = procfile_linewords(ff, l);
50                 if(words < 14) continue;
51
52                 major                   = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
53                 minor                   = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
54                 disk                    = procfile_lineword(ff, l, 2);
55                 reads                   = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
56                 reads_merged    = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
57                 readsectors     = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
58                 readms                  = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
59                 writes                  = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
60                 writes_merged   = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
61                 writesectors    = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
62                 writems                 = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
63                 currentios              = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
64                 iosms                   = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
65                 wiosms                  = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
66
67                 int def_enabled = 0;
68
69                 // remove slashes from disk names
70                 char *s;
71                 for(s = disk; *s ;s++) if(*s == '/') *s = '_';
72
73                 switch(major) {
74                         case 9: // MDs
75                         case 43: // network block
76                         case 144: // nfs
77                         case 145: // nfs
78                         case 146: // nfs
79                         case 199: // veritas
80                         case 201: // veritas
81                         case 251: // dm
82                                 def_enabled = enable_new_disks;
83                                 break;
84
85                         case 48: // RAID
86                         case 49: // RAID
87                         case 50: // RAID
88                         case 51: // RAID
89                         case 52: // RAID
90                         case 53: // RAID
91                         case 54: // RAID
92                         case 55: // RAID
93                         case 112: // RAID
94                         case 136: // RAID
95                         case 137: // RAID
96                         case 138: // RAID
97                         case 139: // RAID
98                         case 140: // RAID
99                         case 141: // RAID
100                         case 142: // RAID
101                         case 143: // RAID
102                         case 179: // MMC
103                         case 180: // USB
104                                 if(minor % 8) def_enabled = 0; // partitions
105                                 else def_enabled = enable_new_disks;
106                                 break;
107
108                         case 8: // scsi disks
109                         case 65: // scsi disks
110                         case 66: // scsi disks
111                         case 67: // scsi disks
112                         case 68: // scsi disks
113                         case 69: // scsi disks
114                         case 70: // scsi disks
115                         case 71: // scsi disks
116                         case 72: // scsi disks
117                         case 73: // scsi disks
118                         case 74: // scsi disks
119                         case 75: // scsi disks
120                         case 76: // scsi disks
121                         case 77: // scsi disks
122                         case 78: // scsi disks
123                         case 79: // scsi disks
124                         case 80: // i2o
125                         case 81: // i2o
126                         case 82: // i2o
127                         case 83: // i2o
128                         case 84: // i2o
129                         case 85: // i2o
130                         case 86: // i2o
131                         case 87: // i2o
132                         case 101: // hyperdisk
133                         case 102: // compressed
134                         case 104: // scsi
135                         case 105: // scsi
136                         case 106: // scsi
137                         case 107: // scsi
138                         case 108: // scsi
139                         case 109: // scsi
140                         case 110: // scsi
141                         case 111: // scsi
142                         case 114: // bios raid
143                         case 116: // ram board
144                         case 128: // scsi
145                         case 129: // scsi
146                         case 130: // scsi
147                         case 131: // scsi
148                         case 132: // scsi
149                         case 133: // scsi
150                         case 134: // scsi
151                         case 135: // scsi
152                         case 153: // raid
153                         case 202: // xen
154                         case 256: // flash
155                         case 257: // flash
156                                 if(minor % 16) def_enabled = 0; // partitions
157                                 else def_enabled = enable_new_disks;
158                                 break;
159
160                         case 160: // raid
161                         case 161: // raid
162                                 if(minor % 32) def_enabled = 0; // partitions
163                                 else def_enabled = enable_new_disks;
164                                 break;
165
166                         case 3: // ide
167                         case 13: // 8bit ide
168                         case 22: // ide
169                         case 33: // ide
170                         case 34: // ide
171                         case 56: // ide
172                         case 57: // ide
173                         case 88: // ide
174                         case 89: // ide
175                         case 90: // ide
176                         case 91: // ide
177                                 if(minor % 64) def_enabled = 0; // partitions
178                                 else def_enabled = enable_new_disks;
179                                 break;
180
181                         default:
182                                 def_enabled = 0;
183                                 break;
184                 }
185
186                 // check if it is enabled
187                 {
188                         char var_name[4096 + 1];
189                         snprintf(var_name, 4096, "disk %s", disk);
190                         if(!config_get_boolean("plugin:proc:/proc/diskstats", var_name, def_enabled)) continue;
191                 }
192
193                 RRDSET *st;
194
195                 // --------------------------------------------------------------------
196
197                 if(do_io) {
198                         st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
199                         if(!st) {
200                                 char tf[FILENAME_MAX + 1], *t;
201                                 char ssfilename[FILENAME_MAX + 1];
202                                 int sector_size = 512;
203
204                                 strncpy(tf, disk, FILENAME_MAX);
205                                 tf[FILENAME_MAX] = '\0';
206
207                                 // replace all / with !
208                                 while((t = strchr(tf, '/'))) *t = '!';
209
210                                 snprintf(ssfilename, FILENAME_MAX, "/sys/block/%s/queue/hw_sector_size", tf);
211                                 FILE *fpss = fopen(ssfilename, "r");
212                                 if(fpss) {
213                                         char ssbuffer[1025];
214                                         char *tmp = fgets(ssbuffer, 1024, fpss);
215
216                                         if(tmp) {
217                                                 sector_size = atoi(tmp);
218                                                 if(sector_size <= 0) {
219                                                         error("Invalid sector size %d for device %s in %s. Assuming 512.", sector_size, disk, ssfilename);
220                                                         sector_size = 512;
221                                                 }
222                                         }
223                                         else error("Cannot read data for sector size for device %s from %s. Assuming 512.", disk, ssfilename);
224
225                                         fclose(fpss);
226                                 }
227                                 else error("Cannot read sector size for device %s from %s. Assuming 512.", disk, ssfilename);
228
229                                 st = rrdset_create(RRD_TYPE_DISK, disk, NULL, disk, "Disk I/O", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
230
231                                 rrddim_add(st, "reads", NULL, sector_size, 1024 * update_every, RRDDIM_INCREMENTAL);
232                                 rrddim_add(st, "writes", NULL, sector_size * -1, 1024 * update_every, RRDDIM_INCREMENTAL);
233                         }
234                         else rrdset_next(st);
235
236                         rrddim_set(st, "reads", readsectors);
237                         rrddim_set(st, "writes", writesectors);
238                         rrdset_done(st);
239                 }
240
241                 // --------------------------------------------------------------------
242
243                 if(do_ops) {
244                         st = rrdset_find_bytype("disk_ops", disk);
245                         if(!st) {
246                                 st = rrdset_create("disk_ops", disk, NULL, disk, "Disk Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
247                                 st->isdetail = 1;
248
249                                 rrddim_add(st, "reads", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
250                                 rrddim_add(st, "writes", NULL, -1, 1 * update_every, RRDDIM_INCREMENTAL);
251                         }
252                         else rrdset_next(st);
253
254                         rrddim_set(st, "reads", reads);
255                         rrddim_set(st, "writes", writes);
256                         rrdset_done(st);
257                 }
258                 
259                 // --------------------------------------------------------------------
260
261                 if(do_merged_ops) {
262                         st = rrdset_find_bytype("disk_merged_ops", disk);
263                         if(!st) {
264                                 st = rrdset_create("disk_merged_ops", disk, NULL, disk, "Merged Disk Operations", "operations/s", 2010, update_every, RRDSET_TYPE_LINE);
265                                 st->isdetail = 1;
266
267                                 rrddim_add(st, "reads", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
268                                 rrddim_add(st, "writes", NULL, -1, 1 * update_every, RRDDIM_INCREMENTAL);
269                         }
270                         else rrdset_next(st);
271
272                         rrddim_set(st, "reads", reads_merged);
273                         rrddim_set(st, "writes", writes_merged);
274                         rrdset_done(st);
275                 }
276
277                 // --------------------------------------------------------------------
278
279                 if(do_iotime) {
280                         st = rrdset_find_bytype("disk_iotime", disk);
281                         if(!st) {
282                                 st = rrdset_create("disk_iotime", disk, NULL, disk, "Disk I/O Time", "milliseconds/s", 2005, update_every, RRDSET_TYPE_LINE);
283                                 st->isdetail = 1;
284
285                                 rrddim_add(st, "reads", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
286                                 rrddim_add(st, "writes", NULL, -1, 1 * update_every, RRDDIM_INCREMENTAL);
287                                 rrddim_add(st, "latency", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
288                                 rrddim_add(st, "weighted", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
289                         }
290                         else rrdset_next(st);
291
292                         rrddim_set(st, "reads", readms);
293                         rrddim_set(st, "writes", writems);
294                         rrddim_set(st, "latency", iosms);
295                         rrddim_set(st, "weighted", wiosms);
296                         rrdset_done(st);
297                 }
298
299                 // --------------------------------------------------------------------
300
301                 if(do_cur_ops) {
302                         st = rrdset_find_bytype("disk_cur_ops", disk);
303                         if(!st) {
304                                 st = rrdset_create("disk_cur_ops", disk, NULL, disk, "Current Disk I/O operations", "operations", 2004, update_every, RRDSET_TYPE_LINE);
305                                 st->isdetail = 1;
306
307                                 rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
308                         }
309                         else rrdset_next(st);
310
311                         rrddim_set(st, "operations", currentios);
312                         rrdset_done(st);
313                 }
314         }
315         
316         return 0;
317 }