handle dynamically added/removed interrupts or softirqs
Also: - store RRDDIM pointers to avoid rrddim_find overhead - fixed some inverted likely/unlikely Signed-off-by: Rémi Lefèvre <remi.lefevre@parrot.com>
Rémi Lefèvre committed
Nov 30, 2016 at 16:55 UTC
409bd68b429f730ba73a750bb6c1bef5f38f6dd8
2 files changed
+110
-55
src/proc_interrupts.c
+55
-27
@@ -2,17 +2,23 @@
2
3
#define MAX_INTERRUPT_NAME 50
4
5
+struct cpu_interrupt {
6
+ unsigned long long value;
7
+ RRDDIM *rd;
8
+};
9
+
10
struct interrupt {
11
int used;
12
char *id;
13
char name[MAX_INTERRUPT_NAME + 1];
14
+ RRDDIM *rd;
15
unsigned long long total;
10
- unsigned long long value[];
16
+ struct cpu_interrupt cpu[];
17
};
18
19
// since each interrupt is variable in size
20
// we use this to calculate its record size
15
-#define recordsize(cpus) (sizeof(struct interrupt) + (cpus * sizeof(unsigned long long)))
21
+#define recordsize(cpus) (sizeof(struct interrupt) + (cpus * sizeof(struct cpu_interrupt)))
22
23
// given a base, get a pointer to each record
24
#define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
@@ -21,8 +27,21 @@ static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
27
static struct interrupt *irrs = NULL;
28
static int allocated = 0;
29
24
- if(unlikely(lines > allocated)) {
30
+ if(unlikely(lines != allocated)) {
31
+ uint32_t l;
32
+ int c;
33
+
34
irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
35
+
36
+ // reset all interrupt RRDDIM pointers as any line could have shifted
37
+ for(l = 0; l < lines ;l++) {
38
+ struct interrupt *irr = irrindex(irrs, l, cpus);
39
+ irr->rd = NULL;
40
+ irr->name[0] = '\0';
41
+ for(c = 0; c < cpus ;c++)
42
+ irr->cpu[c].rd = NULL;
43
+ }
44
+
45
allocated = lines;
46
}
47
@@ -31,7 +50,6 @@ static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
50
51
int do_proc_interrupts(int update_every, unsigned long long dt) {
52
(void)dt;
34
-
53
static procfile *ff = NULL;
54
static int cpus = -1, do_per_core = -1;
55
struct interrupt *irrs = NULL;
@@ -64,7 +82,7 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
82
uint32_t w;
83
cpus = 0;
84
for(w = 0; w < words ; w++) {
67
- if(unlikely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0))
85
+ if(likely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0))
86
cpus++;
87
}
88
}
@@ -96,12 +114,12 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
114
115
int c;
116
for(c = 0; c < cpus ;c++) {
99
- if(unlikely((c + 1) < (int)words))
100
- irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
117
+ if(likely((c + 1) < (int)words))
118
+ irr->cpu[c].value = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
119
else
102
- irr->value[c] = 0;
120
+ irr->cpu[c].value = 0;
121
104
- irr->total += irr->value[c];
122
+ irr->total += irr->cpu[c].value;
123
}
124
125
if(unlikely(isdigit(irr->id[0]) && (uint32_t)(cpus + 2) < words)) {
@@ -124,28 +142,37 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
142
// --------------------------------------------------------------------
143
144
st = rrdset_find_bytype("system", "interrupts");
127
- if(unlikely(!st)) {
128
- st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
129
-
130
- for(l = 0; l < lines ;l++) {
131
- struct interrupt *irr = irrindex(irrs, l, cpus);
132
- if(unlikely(!irr->used)) continue;
133
- rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
134
- }
135
- }
145
+ if(unlikely(!st)) st = rrdset_create("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_STACKED);
146
else rrdset_next(st);
147
148
for(l = 0; l < lines ;l++) {
149
struct interrupt *irr = irrindex(irrs, l, cpus);
150
if(unlikely(!irr->used)) continue;
141
- rrddim_set(st, irr->id, irr->total);
151
+ // some interrupt may have changed without changing the total number of lines
152
+ // if the same number of interrupts have been added and removed between two
153
+ // calls of this function.
154
+ if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
155
+ irr->rd = rrddim_find(st, irr->id);
156
+ if(unlikely(!irr->rd))
157
+ irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
158
+ else
159
+ rrddim_set_name(st, irr->rd, irr->name);
160
+
161
+ // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
162
+ if(likely(do_per_core)) {
163
+ int c;
164
+ for (c = 0; c < cpus ;c++)
165
+ irr->cpu[c].rd = NULL;
166
+ }
167
+ }
168
+ rrddim_set_by_pointer(st, irr->rd, irr->total);
169
}
170
rrdset_done(st);
171
172
if(likely(do_per_core)) {
173
int c;
174
148
- for(c = 0; c < cpus ; c++) {
175
+ for(c = 0; c < cpus ;c++) {
176
char id[50+1];
177
snprintfz(id, 50, "cpu%d_interrupts", c);
178
@@ -154,19 +181,20 @@ int do_proc_interrupts(int update_every, unsigned long long dt) {
181
char title[100+1];
182
snprintfz(title, 100, "CPU%d Interrupts", c);
183
st = rrdset_create("cpu", id, NULL, "interrupts", "cpu.interrupts", title, "interrupts/s", 1100 + c, update_every, RRDSET_TYPE_STACKED);
157
-
158
- for(l = 0; l < lines ;l++) {
159
- struct interrupt *irr = irrindex(irrs, l, cpus);
160
- if(unlikely(!irr->used)) continue;
161
- rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
162
- }
184
}
185
else rrdset_next(st);
186
187
for(l = 0; l < lines ;l++) {
188
struct interrupt *irr = irrindex(irrs, l, cpus);
189
if(unlikely(!irr->used)) continue;
169
- rrddim_set(st, irr->id, irr->value[c]);
190
+ if(unlikely(!irr->cpu[c].rd)) {
191
+ irr->cpu[c].rd = rrddim_find(st, irr->id);
192
+ if(unlikely(!irr->cpu[c].rd))
193
+ irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
194
+ else
195
+ rrddim_set_name(st, irr->cpu[c].rd, irr->name);
196
+ }
197
+ rrddim_set_by_pointer(st, irr->cpu[c].rd, irr->cpu[c].value);
198
}
199
rrdset_done(st);
200
}
src/proc_softirqs.c
+55
-28
@@ -2,17 +2,23 @@
2
3
#define MAX_INTERRUPT_NAME 50
4
5
+struct cpu_interrupt {
6
+ unsigned long long value;
7
+ RRDDIM *rd;
8
+};
9
+
10
struct interrupt {
11
int used;
12
char *id;
13
char name[MAX_INTERRUPT_NAME + 1];
14
+ RRDDIM *rd;
15
unsigned long long total;
10
- unsigned long long value[];
16
+ struct cpu_interrupt cpu[];
17
};
18
19
// since each interrupt is variable in size
20
// we use this to calculate its record size
15
-#define recordsize(cpus) (sizeof(struct interrupt) + (cpus * sizeof(unsigned long long)))
21
+#define recordsize(cpus) (sizeof(struct interrupt) + (cpus * sizeof(struct cpu_interrupt)))
22
23
// given a base, get a pointer to each record
24
#define irrindex(base, line, cpus) ((struct interrupt *)&((char *)(base))[line * recordsize(cpus)])
@@ -21,8 +27,21 @@ static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
27
static struct interrupt *irrs = NULL;
28
static int allocated = 0;
29
24
- if(unlikely(lines > allocated)) {
30
+ if(unlikely(lines != allocated)) {
31
+ uint32_t l;
32
+ int c;
33
+
34
irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
35
+
36
+ // reset all interrupt RRDDIM pointers as any line could have shifted
37
+ for(l = 0; l < lines ;l++) {
38
+ struct interrupt *irr = irrindex(irrs, l, cpus);
39
+ irr->rd = NULL;
40
+ irr->name[0] = '\0';
41
+ for(c = 0; c < cpus ;c++)
42
+ irr->cpu[c].rd = NULL;
43
+ }
44
+
45
allocated = lines;
46
}
47
@@ -31,10 +50,8 @@ static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
50
51
int do_proc_softirqs(int update_every, unsigned long long dt) {
52
(void)dt;
34
-
53
static procfile *ff = NULL;
54
static int cpus = -1, do_per_core = -1;
37
-
55
struct interrupt *irrs = NULL;
56
57
if(unlikely(do_per_core == -1)) do_per_core = config_get_boolean("plugin:proc:/proc/softirqs", "interrupts per core", 1);
@@ -62,7 +79,7 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
79
uint32_t w;
80
cpus = 0;
81
for(w = 0; w < words ; w++) {
65
- if(unlikely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0))
82
+ if(likely(strncmp(procfile_lineword(ff, 0, w), "CPU", 3) == 0))
83
cpus++;
84
}
85
}
@@ -94,12 +111,12 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
111
112
int c;
113
for(c = 0; c < cpus ;c++) {
97
- if(unlikely((c + 1) < (int)words))
98
- irr->value[c] = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
114
+ if(likely((c + 1) < (int)words))
115
+ irr->cpu[c].value = strtoull(procfile_lineword(ff, l, (uint32_t)(c + 1)), NULL, 10);
116
else
100
- irr->value[c] = 0;
117
+ irr->cpu[c].value = 0;
118
102
- irr->total += irr->value[c];
119
+ irr->total += irr->cpu[c].value;
120
}
121
122
strncpyz(irr->name, irr->id, MAX_INTERRUPT_NAME);
@@ -112,21 +129,30 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
129
// --------------------------------------------------------------------
130
131
st = rrdset_find_bytype("system", "softirqs");
115
- if(unlikely(!st)) {
116
- st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
117
-
118
- for(l = 0; l < lines ;l++) {
119
- struct interrupt *irr = irrindex(irrs, l, cpus);
120
- if(unlikely(!irr->used)) continue;
121
- rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
122
- }
123
- }
132
+ if(unlikely(!st)) st = rrdset_create("system", "softirqs", NULL, "softirqs", NULL, "System softirqs", "softirqs/s", 950, update_every, RRDSET_TYPE_STACKED);
133
else rrdset_next(st);
134
135
for(l = 0; l < lines ;l++) {
136
struct interrupt *irr = irrindex(irrs, l, cpus);
137
if(unlikely(!irr->used)) continue;
129
- rrddim_set(st, irr->id, irr->total);
138
+ // some interrupt may have changed without changing the total number of lines
139
+ // if the same number of interrupts have been added and removed between two
140
+ // calls of this function.
141
+ if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
142
+ irr->rd = rrddim_find(st, irr->id);
143
+ if(unlikely(!irr->rd))
144
+ irr->rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
145
+ else
146
+ rrddim_set_name(st, irr->rd, irr->name);
147
+
148
+ // also reset per cpu RRDDIMs to avoid repeating strncmp() in the per core loop
149
+ if(likely(do_per_core)) {
150
+ int c;
151
+ for (c = 0; c < cpus ;c++)
152
+ irr->cpu[c].rd = NULL;
153
+ }
154
+ }
155
+ rrddim_set_by_pointer(st, irr->rd, irr->total);
156
}
157
rrdset_done(st);
158
@@ -144,26 +170,27 @@ int do_proc_softirqs(int update_every, unsigned long long dt) {
170
for(l = 0; l < lines ;l++) {
171
struct interrupt *irr = irrindex(irrs, l, cpus);
172
if(unlikely(!irr->used)) continue;
147
- core_sum += irr->value[c];
173
+ core_sum += irr->cpu[c].value;
174
}
175
if(unlikely(core_sum == 0)) continue; // try next core
176
177
char title[100+1];
178
snprintfz(title, 100, "CPU%d softirqs", c);
179
st = rrdset_create("cpu", id, NULL, "softirqs", "cpu.softirqs", title, "softirqs/s", 3000 + c, update_every, RRDSET_TYPE_STACKED);
154
-
155
- for(l = 0; l < lines ;l++) {
156
- struct interrupt *irr = irrindex(irrs, l, cpus);
157
- if(unlikely(!irr->used)) continue;
158
- rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
159
- }
180
}
181
else rrdset_next(st);
182
183
for(l = 0; l < lines ;l++) {
184
struct interrupt *irr = irrindex(irrs, l, cpus);
185
if(unlikely(!irr->used)) continue;
166
- rrddim_set(st, irr->id, irr->value[c]);
186
+ if(unlikely(!irr->cpu[c].rd)) {
187
+ irr->cpu[c].rd = rrddim_find(st, irr->id);
188
+ if(unlikely(!irr->cpu[c].rd))
189
+ irr->cpu[c].rd = rrddim_add(st, irr->id, irr->name, 1, 1, RRDDIM_INCREMENTAL);
190
+ else
191
+ rrddim_set_name(st, irr->cpu[c].rd, irr->name);
192
+ }
193
+ rrddim_set_by_pointer(st, irr->cpu[c].rd, irr->cpu[c].value);
194
}
195
rrdset_done(st);
196
}