tc: optimized memory usage
Costa Tsaousis (ktsaou) committed
Apr 4, 2015 at 05:57 UTC
ed44ce7b87de9070f5ecb27a15198807cd0c55d5
2 files changed
+85
-29
src/daemon.c
+2
-2
@@ -69,9 +69,9 @@ char pidfile[FILENAME_MAX + 1] = "";
69
void prepare_rundir() {
70
if(getuid() != 0) {
71
mkdir("/run/user", 0775);
72
- snprintf(rundir, FILENAME_MAX, "/run/user/%d", getpid());
72
+ snprintf(rundir, FILENAME_MAX, "/run/user/%d", getuid());
73
mkdir(rundir, 0775);
74
- snprintf(rundir, FILENAME_MAX, "/run/user/%d/netdata", getpid());
74
+ snprintf(rundir, FILENAME_MAX, "/run/user/%d/netdata", getuid());
75
}
76
77
snprintf(pidfile, FILENAME_MAX, "%s/netdata.pid", rundir);
src/plugin_tc.c
+83
-27
@@ -38,9 +38,11 @@ struct tc_class {
38
char isleaf;
39
unsigned long long bytes;
40
41
- char updated;
41
+ char updated; // updated bytes
42
+ char seen; // seen in the tc list (even without bytes)
43
44
struct tc_class *next;
45
+ struct tc_class *prev;
46
};
47
48
struct tc_device {
@@ -112,6 +114,48 @@ static struct tc_class *tc_class_index_find(struct tc_device *st, const char *id
114
115
// ----------------------------------------------------------------------------
116
117
+static void tc_class_free(struct tc_device *n, struct tc_class *c) {
118
+ debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', seen=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->seen);
119
+
120
+ if(c->next) c->next->prev = c->prev;
121
+ if(c->prev) c->prev->next = c->next;
122
+ if(n->classes == c) n->classes = c->next;
123
+
124
+ tc_class_index_del(n, c);
125
+
126
+ if(c->id) free(c->id);
127
+ if(c->name) free(c->name);
128
+ if(c->leafid) free(c->leafid);
129
+ if(c->parentid) free(c->parentid);
130
+
131
+ free(c);
132
+}
133
+
134
+static void tc_device_classes_cleanup(struct tc_device *d) {
135
+ static int cleanup_every = 999;
136
+
137
+ if(cleanup_every > 0) {
138
+ cleanup_every = -config_get_number("plugin:tc", "cleanup unused classes every", 60);
139
+ if(cleanup_every > 0) cleanup_every = -cleanup_every;
140
+ if(cleanup_every == 0) cleanup_every = -1;
141
+ }
142
+
143
+ struct tc_class *c = d->classes;
144
+ while(c) {
145
+ if(c->seen < cleanup_every) {
146
+ struct tc_class *nc = c->next;
147
+ tc_class_free(d, c);
148
+ c = nc;
149
+ }
150
+ else c = c->next;
151
+
152
+ if(c) {
153
+ c->updated = 0;
154
+ c->seen--;
155
+ }
156
+ }
157
+}
158
+
159
static void tc_device_commit(struct tc_device *d)
160
{
161
static int enable_new_interfaces = -1;
@@ -121,7 +165,7 @@ static void tc_device_commit(struct tc_device *d)
165
// we only need to add leaf classes
166
struct tc_class *c, *x;
167
124
- // set them all as leafs without parent
168
+ // set all classes
169
for(c = d->classes ; c ; c = c->next) {
170
c->isleaf = 1;
171
c->hasparent = 0;
@@ -134,10 +178,12 @@ static void tc_device_commit(struct tc_device *d)
178
for(x = d->classes ; x ; x = x->next) {
179
if(!x->updated) continue;
180
181
+ if(c == x) continue;
182
+
183
if(x->parentid && (
184
( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
185
(c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
140
- // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has leaf the class '%s' (parentid: '%s').", d->name, c->name, c->leafid, x->name, x->parentid);
186
+ // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has as leaf class '%s' (parentid: '%s').", d->name?d->name:d->id, c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->name?x->name:x->id, x->parentid?x->parentid:x->id);
187
c->isleaf = 0;
188
x->hasparent = 1;
189
}
@@ -152,13 +198,15 @@ static void tc_device_commit(struct tc_device *d)
198
}
199
*/
200
155
- // we need a device
201
+ // we need at least a class
202
for(c = d->classes ; c ; c = c->next) {
203
+ // debug(D_TC_LOOP, "TC: Device '%s', class '%s', isLeaf=%d, HasParent=%d, Seen=%d", d->name?d->name:d->id, c->name?c->name:c->id, c->isleaf, c->hasparent, c->seen);
204
if(!c->updated) continue;
205
if(c->isleaf && c->hasparent) break;
206
}
207
if(!c) {
208
debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
209
+ tc_device_classes_cleanup(d);
210
return;
211
}
212
@@ -167,7 +215,7 @@ static void tc_device_commit(struct tc_device *d)
215
if(config_get_boolean("plugin:tc", var_name, enable_new_interfaces)) {
216
RRDSET *st = rrdset_find_bytype(RRD_TYPE_TC, d->id);
217
if(!st) {
170
- debug(D_TC_LOOP, "TC: Committing new TC device '%s'", d->name?d->name:d->id);
218
+ debug(D_TC_LOOP, "TC: Creating new chart for device '%s'", d->name?d->name:d->id);
219
220
st = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, "Class Usage", "kilobits/s", 1000, rrd_update_every, RRDSET_TYPE_STACKED);
221
@@ -179,6 +227,7 @@ static void tc_device_commit(struct tc_device *d)
227
}
228
}
229
else {
230
+ debug(D_TC_LOOP, "TC: Updating chart for device '%s'", d->name?d->name:d->id);
231
rrdset_next_plugins(st);
232
233
if(d->name && strcmp(d->id, d->name) != 0) rrdset_set_name(st, d->name);
@@ -189,27 +238,32 @@ static void tc_device_commit(struct tc_device *d)
238
239
if(c->isleaf && c->hasparent) {
240
if(rrddim_set(st, c->id, c->bytes) != 0) {
241
+ debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s'", st->id, c->id, c->name);
242
243
// new class, we have to add it
244
rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
245
rrddim_set(st, c->id, c->bytes);
246
}
247
+ else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", st->id, c->id);
248
249
// if it has a name, different to the id
250
if(c->name) {
251
// update the rrd dimension with the new name
252
RRDDIM *rd = rrddim_find(st, c->id);
202
- if(rd) rrddim_set_name(st, rd, c->name);
253
+ if(rd) {
254
+ debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", st->id, rd->id, c->name);
255
+ rrddim_set_name(st, rd, c->name);
256
+ }
257
258
free(c->name);
259
c->name = NULL;
260
}
261
}
208
-
209
- c->updated = 0;
262
}
263
rrdset_done(st);
264
}
265
+
266
+ tc_device_classes_cleanup(d);
267
}
268
269
static void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
@@ -219,7 +273,10 @@ static void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
273
if(c->name) free(c->name);
274
c->name = NULL;
275
222
- if(name && *name && strcmp(c->id, name) != 0) c->name = strdup(name);
276
+ if(name && *name && strcmp(c->id, name) != 0) {
277
+ debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
278
+ c->name = strdup(name);
279
+ }
280
}
281
}
282
@@ -227,14 +284,20 @@ static void tc_device_set_device_name(struct tc_device *d, char *name) {
284
if(d->name) free(d->name);
285
d->name = NULL;
286
230
- if(name && *name && strcmp(d->id, name) != 0) d->name = strdup(name);
287
+ if(name && *name && strcmp(d->id, name) != 0) {
288
+ debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
289
+ d->name = strdup(name);
290
+ }
291
}
292
293
static void tc_device_set_device_family(struct tc_device *d, char *family) {
294
if(d->family) free(d->family);
295
d->family = NULL;
296
237
- if(family && *family && strcmp(d->id, family) != 0) d->family = strdup(family);
297
+ if(family && *family && strcmp(d->id, family) != 0) {
298
+ debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
299
+ d->family = strdup(family);
300
+ }
301
// no need for null termination - it is already null
302
}
303
@@ -243,6 +306,7 @@ static struct tc_device *tc_device_create(char *id)
306
struct tc_device *d = tc_device_index_find(id, 0);
307
308
if(!d) {
309
+ debug(D_TC_LOOP, "TC: Creating device '%s'", id);
310
311
d = calloc(1, sizeof(struct tc_device));
312
if(!d) {
@@ -264,16 +328,18 @@ static struct tc_device *tc_device_create(char *id)
328
329
static struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
330
{
267
- // fprintf(stderr, "Adding class id '%s', parentid '%s', leafid '%s'\n", id, parentid, leafid);
268
-
331
struct tc_class *c = tc_class_index_find(n, id, 0);
332
+
333
if(!c) {
334
+ debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
335
+
336
c = calloc(1, sizeof(struct tc_class));
337
if(!c) {
338
fatal("Cannot allocate memory for tc class");
339
return NULL;
340
}
341
342
+ if(n->classes) n->classes->prev = c;
343
c->next = n->classes;
344
n->classes = c;
345
@@ -297,26 +363,16 @@ static struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parent
363
tc_class_index_add(n, c);
364
}
365
366
+ c->seen = 1;
367
+
368
return(c);
369
}
370
/*
303
-static void tc_class_free_all(struct tc_device *n, struct tc_class *c)
304
-{
305
- if(c->next) tc_class_free_all(n, c->next);
306
- tc_class_index_del(n, c);
307
-
308
- if(c->id) free(c->id);
309
- if(c->name) free(c->name);
310
- if(c->leafid) free(c->leafid);
311
- if(c->parentid) free(c->parentid);
312
-
313
- free(c);
314
-}
315
-
371
static void tc_device_free(struct tc_device *n)
372
{
373
tc_device_index_del(n);
319
- if(n->classes) tc_class_free_all(n, n->classes);
374
+
375
+ while(n->classes) tc_class_free(n, n->classes);
376
377
if(n->id) free(n->id);
378
if(n->name) free(n->name);