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