@cryptotaxi247 / netdata-1 / commits / 409bd68b4

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 }