]> arthur.barton.de Git - netdata.git/blob - src/proc_interrupts.c
added /proc/interrupts #12
[netdata.git] / src / proc_interrupts.c
1 #include <inttypes.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6
7 #include "config.h"
8 #include "procfile.h"
9 #include "rrd.h"
10 #include "plugin_proc.h"
11 #include "log.h"
12
13 #define MAX_INTERRUPTS 256
14 #define MAX_INTERRUPT_CPUS 256
15 #define MAX_INTERRUPT_NAME 20
16
17 struct interrupt {
18         int used;
19         char *id;
20         char *name;
21         unsigned long long value[MAX_INTERRUPT_CPUS];
22         unsigned long long total;
23 };
24
25 int do_proc_interrupts(int update_every, unsigned long long dt) {
26         static procfile *ff = NULL;
27         static int cpus = -1, do_per_core = -1;
28
29         if(dt) {};
30
31         if(do_per_core == -1) do_per_core = config_get_boolean("plugin:proc:/proc/interrupts", "interrupts per core", 1);
32
33         if(!ff) ff = procfile_open("/proc/interrupts", " \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 = procfile_linewords(ff, 0), w;
41
42         // find how many CPUs are there
43         if(cpus == -1) {
44                 cpus = 0;
45                 for(w = 0; w < words ; w++) {
46                         if(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0)
47                                 cpus++;
48                 }
49
50                 if(cpus > MAX_INTERRUPT_CPUS) cpus = MAX_INTERRUPT_CPUS;
51         }
52
53         if(!cpus) {
54                 error("PLUGIN: PROC_INTERRUPTS: Cannot find the number of CPUs in /proc/interrupts");
55                 return 1;
56         }
57
58         // allocate the size we need;
59         struct interrupt irrs[lines];
60         irrs[0].used = 0;
61
62         // loop through all lines
63         for(l = 1; l < lines ;l++) {
64                 struct interrupt *irr = &irrs[l];
65                 irr->used = 0;
66                 irr->total = 0;
67
68                 words = procfile_linewords(ff, l);
69                 if(!words) continue;
70
71                 irr->id = procfile_lineword(ff, l, 0);
72                 if(!irr->id || !irr->id[0]) continue;
73
74                 if(irr->id[strlen(irr->id) - 1] == ':')
75                         irr->id[strlen(irr->id) - 1] = '\0';
76
77                 int c;
78                 for(c = 0; c < cpus ;c++) {
79                         if((c + 1) < (int)words)
80                                 irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
81                         else
82                                 irr->value[c] = 0;
83
84                         irr->total += irr->value[c];
85                 }
86
87                 if(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words) {
88                         irr->name = procfile_lineword(ff, l, words - 1);
89                 }
90                 else
91                         irr->name = irr->id;
92
93                 irr->used = 1;
94         }
95
96         RRDSET *st;
97
98         // --------------------------------------------------------------------
99
100         st = rrdset_find_bytype("system", "interrupts");
101         if(!st) {
102                 st = rrdset_create("system", "interrupts", NULL, "system", "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
103
104                 for(l = 0; l < lines ;l++) {
105                         if(!irrs[l].used) continue;
106                         rrddim_add(st, irrs[l].id, irrs[l].name, 1, update_every, RRDDIM_INCREMENTAL);
107                 }
108         }
109         else rrdset_next(st);
110
111         for(l = 0; l < lines ;l++) {
112                 if(!irrs[l].used) continue;
113                 rrddim_set(st, irrs[l].id, irrs[l].total);
114         }
115         rrdset_done(st);
116
117         if(do_per_core) {
118                 int c;
119
120                 for(c = 0; c < cpus ; c++) {
121                         char id[256];
122                         snprintf(id, 256, "cpu%d_interrupts", c);
123
124                         st = rrdset_find_bytype("cpu", id);
125                         if(!st) {
126                                 char name[256], title[256];
127                                 snprintf(name, 256, "cpu%d_interrupts", c);
128                                 snprintf(title, 256, "CPU%d Interrupts", c);
129                                 st = rrdset_create("cpu", id, name, "cpu", title, "interrupts/s", 2000 + c, update_every, RRDSET_TYPE_STACKED);
130
131                                 for(l = 0; l < lines ;l++) {
132                                         if(!irrs[l].used) continue;
133                                         rrddim_add(st, irrs[l].id, irrs[l].name, 1, update_every, RRDDIM_INCREMENTAL);
134                                 }
135                         }
136                         else rrdset_next(st);
137
138                         for(l = 0; l < lines ;l++) {
139                                 if(!irrs[l].used) continue;
140                                 rrddim_set(st, irrs[l].id, irrs[l].value[c]);
141                         }
142                         rrdset_done(st);
143                 }
144         }
145
146         return 0;
147 }