Annotation of embedaddon/bmon/src/attr.c, revision 1.1.1.2
1.1 misho 1: /*
2: * attr.c Attributes
3: *
4: * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
5: * Copyright (c) 2013 Red Hat, Inc.
6: *
7: * Permission is hereby granted, free of charge, to any person obtaining a
8: * copy of this software and associated documentation files (the "Software"),
9: * to deal in the Software without restriction, including without limitation
10: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11: * and/or sell copies of the Software, and to permit persons to whom the
12: * Software is furnished to do so, subject to the following conditions:
13: *
14: * The above copyright notice and this permission notice shall be included
15: * in all copies or substantial portions of the Software.
16: *
17: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23: * DEALINGS IN THE SOFTWARE.
24: */
25:
26: #include <bmon/bmon.h>
27: #include <bmon/conf.h>
28: #include <bmon/attr.h>
29: #include <bmon/history.h>
30: #include <bmon/element.h>
31: #include <bmon/unit.h>
32: #include <bmon/input.h>
33: #include <bmon/utils.h>
34:
35: #if 0
36:
37: #define MAX_POLICY 255
38:
39: static char * allowed_attrs[MAX_POLICY];
40: static char * denied_attrs[MAX_POLICY];
41: static int allow_all_attrs;
42:
43: #endif
44:
45: static LIST_HEAD(attr_def_list);
46: static int attr_id_gen = 1;
47:
48: struct attr_def *attr_def_lookup(const char *name)
49: {
50: struct attr_def *def;
51:
52: list_for_each_entry(def, &attr_def_list, ad_list)
53: if (!strcmp(name, def->ad_name))
54: return def;
55:
56: return NULL;
57: }
58:
59: struct attr_def *attr_def_lookup_id(int id)
60: {
61: struct attr_def *def;
62:
63: list_for_each_entry(def, &attr_def_list, ad_list)
64: if (def->ad_id == id)
65: return def;
66:
67: return NULL;
68: }
69:
70: #if 0
71: int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
72: {
73: int i, err = 0;
74:
75: for (i = 0; i < NAME_HASHSIZ; i++) {
76: struct attr_type *t;
77: for (t = attr_ht_name[i]; t; t = t->at_next_name) {
78: err = cb(t, arg);
79: if (err < 0)
80: break;
81: }
82: }
83:
84: return err;
85: }
86: #endif
87:
88: int attr_def_add(const char *name, const char *desc, struct unit *unit,
89: int type, int flags)
90: {
91: struct attr_def *def;
92:
93: if ((def = attr_def_lookup(name)))
94: return def->ad_id;
95:
96: def = xcalloc(1, sizeof(*def));
97:
98: def->ad_id = attr_id_gen++;
99: def->ad_name = strdup(name);
100:
101: def->ad_description = strdup(desc ? : "");
102: def->ad_type = type;
103: def->ad_unit = unit;
104: def->ad_flags = flags;
105:
106: list_add_tail(&def->ad_list, &attr_def_list);
107:
108: DBG("New attribute %s desc=\"%s\" unit=%s type=%d",
109: def->ad_name, def->ad_description, def->ad_unit->u_name, type);
110:
111: return def->ad_id;
112: }
113:
1.1.1.2 ! misho 114: static void attr_def_free(struct attr_def *def)
1.1 misho 115: {
116: if (!def)
117: return;
118:
119: xfree(def->ad_name);
120: xfree(def->ad_description);
121: xfree(def);
122: }
123:
124: int attr_map_load(struct attr_map *map, size_t size)
125: {
126: int i, nfailed = 0;
127:
128: for (i = 0; i < size; i++) {
129: struct attr_map *m = &map[i];
130: struct unit *u;
131:
132: if (!(u = unit_lookup(m->unit))) {
133: nfailed++;
134: continue;
135: }
136:
137: m->attrid = attr_def_add(m->name, m->description, u,
138: m->type, m->flags);
139: }
140:
141: return nfailed;
142: }
143:
144: static inline unsigned int attr_hash(int id)
145: {
146: return id % ATTR_HASH_SIZE;
147: }
148:
149: struct attr *attr_lookup(const struct element *e, int id)
150: {
151: unsigned int hash = attr_hash(id);
152: struct attr *attr;
153:
154: list_for_each_entry(attr, &e->e_attrhash[hash], a_list)
155: if (attr->a_def->ad_id == id)
156: return attr;
157:
158: return NULL;
159: }
160:
161: static int collect_history(struct element *e, struct attr_def *def)
162: {
163: int n;
164:
165: if (def->ad_flags & ATTR_FORCE_HISTORY)
166: return 1;
167:
168: for (n = 0; n <= GT_MAX; n++)
169: if (e->e_key_attr[n] == def)
170: return 1;
171:
172: return 0;
173: #if 0
174: if (!allowed_attrs[0] && !denied_attrs[0]) {
175: if (!strcmp(ad->ad_name, "bytes") ||
176: !strcmp(ad->ad_name, "packets"))
177: return 1;
178: else
179: return 0;
180: }
181:
182: if (!allowed_attrs[0]) {
183: for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
184: if (!strcasecmp(denied_attrs[n], ad->ad_name))
185: return 0;
186: return 1;
187: }
188:
189: for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
190: if (!strcasecmp(denied_attrs[n], ad->ad_name))
191: return 0;
192:
193: for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
194: if (!strcasecmp(allowed_attrs[n], ad->ad_name))
195: return 1;
196: #endif
197: }
198:
199: #if 0
200:
201: void attr_parse_policy(const char *policy)
202: {
203: static int set = 0;
204: int i, a = 0, d = 0, f = 0;
205: char *p, *s;
206:
207: if (set)
208: return;
209: set = 1;
210:
211: if (!strcasecmp(policy, "all")) {
212: allow_all_attrs = 1;
213: return ;
214: }
215:
216: s = strdup(policy);
217:
218: for (i = 0, p = s; ; i++) {
219: if (s[i] == ',' || s[i] == '\0') {
220:
221: f = s[i] == '\0' ? 1 : 0;
222: s[i] = '\0';
223:
224: if ('!' == *p) {
225: if (d > (MAX_POLICY - 1))
226: break;
227: denied_attrs[d++] = strdup(++p);
228: } else {
229: if(a > (MAX_POLICY - 1))
230: break;
231: allowed_attrs[a++] = strdup(p);
232: }
233:
234: if (f)
235: break;
236:
237: p = &s[i+1];
238: }
239: }
240:
241: xfree(s);
242: }
243:
244: #endif
245:
246: void attr_start_collecting_history(struct attr *attr)
247: {
248: if (attr->a_flags & ATTR_DOING_HISTORY)
249: return;
250:
251: DBG("Starting to collect history for attribute %s",
252: attr->a_def->ad_name);
253:
254: history_attach(attr);
255: attr->a_flags |= ATTR_DOING_HISTORY;
256: }
257:
258: static int attrcmp(struct element *e, struct attr *a, struct attr *b)
259: {
260: /* major key attribute is always first */
261: if (e->e_key_attr[GT_MAJOR] == b->a_def)
262: return 1;
263:
264: /* minor key attribte is always second */
265: if (e->e_key_attr[GT_MINOR] == b->a_def)
266: return (e->e_key_attr[GT_MAJOR] == a->a_def) ? -1 : 1;
267:
268: /* otherwise sort by alphabet */
269: return strcasecmp(a->a_def->ad_description, b->a_def->ad_description);
270: }
271:
272: void attr_update(struct element *e, int id, uint64_t rx, uint64_t tx, int flags)
273: {
274: struct attr *attr, *n;
275: int update_ts = 0;
276:
277: if (!(attr = attr_lookup(e, id))) {
278: unsigned int hash = attr_hash(id);
279: struct attr_def *def;
280:
281: if (!(def = attr_def_lookup_id(id)))
282: return;
283:
284: DBG("Tracking new attribute %d (\"%s\") of element %s",
285: def->ad_id, def->ad_name, e->e_name);
286:
287: attr = xcalloc(1, sizeof(*attr));
288: attr->a_def = def;
289: attr->a_flags = def->ad_flags;
290:
291: init_list_head(&attr->a_history_list);
292:
293: if (collect_history(e, def))
294: attr_start_collecting_history(attr);
295:
296: list_add_tail(&attr->a_list, &e->e_attrhash[hash]);
297: e->e_nattrs++;
298:
299: list_for_each_entry(n, &e->e_attr_sorted, a_sort_list) {
300: if (attrcmp(e, attr, n) < 0) {
301: list_add_tail(&attr->a_sort_list,
302: &n->a_sort_list);
303: goto inserted;
304: }
305: }
306:
307: list_add_tail(&attr->a_sort_list, &e->e_attr_sorted);
308: }
309:
310: inserted:
311: if (flags & UPDATE_FLAG_RX) {
312: attr->a_rx_rate.r_current = rx;
313: attr->a_flags |= ATTR_RX_ENABLED;
314: update_ts = 1;
315: }
316:
317: if (flags & UPDATE_FLAG_TX) {
318: attr->a_tx_rate.r_current = tx;
319: attr->a_flags |= ATTR_TX_ENABLED;
320: update_ts = 1;
321: }
322:
323: if (update_ts)
324: update_timestamp(&attr->a_last_update);
325:
326: DBG("Updated attribute %d (\"%s\") of element %s", id, attr->a_def->ad_name, e->e_name);
327: }
328:
329: void attr_free(struct attr *a)
330: {
331: struct history *h, *n;
332:
333: list_for_each_entry_safe(h, n, &a->a_history_list, h_list)
334: history_free(h);
335:
336: list_del(&a->a_list);
337:
338: xfree(a);
339: }
340:
341: void attr_rate2float(struct attr *a, double *rx, char **rxu, int *rxprec,
342: double *tx, char **txu, int *txprec)
343: {
344: struct unit *u = a->a_def->ad_unit;
345:
346: *rx = unit_value2str(a->a_rx_rate.r_rate, u, rxu, rxprec);
347: *tx = unit_value2str(a->a_tx_rate.r_rate, u, txu, txprec);
348: }
349:
350: struct attr *attr_select_first(void)
351: {
352: struct element *e;
353:
354: if (!(e = element_current()))
355: return NULL;
356:
357: if (list_empty(&e->e_attr_sorted))
358: e->e_current_attr = NULL;
359: else
360: e->e_current_attr = list_first_entry(&e->e_attr_sorted,
361: struct attr, a_sort_list);
362:
363: return e->e_current_attr;
364: }
365:
366: struct attr *attr_select_last(void)
367: {
368: struct element *e;
369:
370: if (!(e = element_current()))
371: return NULL;
372:
373: if (list_empty(&e->e_attr_sorted))
374: e->e_current_attr = NULL;
375: else
376: e->e_current_attr = list_entry(&e->e_attr_sorted,
377: struct attr, a_sort_list);
378:
379: return e->e_current_attr;
380: }
381:
382: struct attr *attr_select_next(void)
383: {
384: struct element *e;
385: struct attr *a;
386:
387: if (!(e = element_current()))
388: return NULL;
389:
390: if (!(a = e->e_current_attr))
391: return attr_select_first();
392:
393: if (a->a_sort_list.next != &e->e_attr_sorted)
394: e->e_current_attr = list_entry(a->a_sort_list.next,
395: struct attr, a_sort_list);
396: else
397: return attr_select_first();
398:
399: return e->e_current_attr;
400: }
401:
402: struct attr *attr_select_prev(void)
403: {
404: struct element *e;
405: struct attr *a;
406:
407: if (!(e = element_current()))
408: return NULL;
409:
410: if (!(a = e->e_current_attr))
411: return attr_select_last();
412:
413: if (a->a_sort_list.prev != &e->e_attr_sorted)
414: e->e_current_attr = list_entry(a->a_sort_list.prev,
415: struct attr, a_sort_list);
416: else
417: return attr_select_last();
418:
419: return e->e_current_attr;
420:
421: }
422:
423: struct attr *attr_current(void)
424: {
425: struct element *e;
426:
427: if (!(e = element_current()))
428: return NULL;
429:
430: if (!e->e_current_attr)
431: return attr_select_first();
432:
433: return e->e_current_attr;
434: }
435:
436: #if 0
437: int __first_attr(struct item *item, int graph)
438: {
439: int i;
440: struct attr *a;
441:
442: for (i = 0; i < ATTR_HASH_MAX; i++) {
443: for (a = item->i_attrs[i]; a; a = a->a_next) {
444: if (a->a_flags & ATTR_FLAG_HISTORY) {
445: item->i_attr_sel[graph] = a;
446: return 0;
447: }
448: }
449: }
450:
451: return EMPTY_LIST;
452: }
453:
454: int __next_attr(struct item *item, int graph)
455: {
456: int hash;
457: struct attr *attr, *next;
458:
459: if (item->i_attr_sel[graph] == NULL)
460: return __first_attr(item, graph);
461:
462: attr = item->i_attr_sel[graph];
463: hash = attr_hash(attr->a_def->ad_id);
464: next = attr->a_next;
465:
466: if (next == NULL)
467: hash++;
468:
469: for (; hash < ATTR_HASH_MAX; hash++) {
470: if (next) {
471: attr = next;
472: next = NULL;
473: } else
474: attr = item->i_attrs[hash];
475:
476: for (; attr; attr = attr->a_next) {
477: if (!(attr->a_flags & ATTR_FLAG_HISTORY))
478: continue;
479: item->i_attr_sel[graph] = attr;
480: return 0;
481: }
482: }
483:
484: return __first_attr(item, graph);
485: }
486:
487: struct attr *attr_current(struct item *item, int graph)
488: {
489: if (item->i_attr_sel[graph] == NULL)
490: __first_attr(item, graph);
491:
492: return item->i_attr_sel[graph];
493: }
494:
495: int attr_first(void)
496: {
497: struct item *item = item_current();
498:
499: if (item == NULL)
500: return EMPTY_LIST;
501:
502: return __first_attr(item, item->i_graph_sel);
503: }
504:
505: int attr_next(void)
506: {
507: struct item *item = item_current();
508:
509: if (item == NULL)
510: return EMPTY_LIST;
511:
512: return __next_attr(item, item->i_graph_sel);
513: }
514: #endif
515:
516: static float __calc_usage(double rate, uint64_t max)
517: {
518: if (!max)
519: return FLT_MAX;
520:
521: if (!rate)
522: return 0.0f;
523:
524: return 100.0f / ((double) max / (rate * cfg_rate_interval));
525: }
526:
1.1.1.2 ! misho 527: uint64_t rate_get_total(struct rate *r)
! 528: {
! 529: return r->r_total - r->r_reset;
! 530: }
! 531:
1.1 misho 532: void attr_calc_usage(struct attr *a, float *rx, float *tx,
533: uint64_t rxmax, uint64_t txmax)
534: {
535: if (a->a_def->ad_type == ATTR_TYPE_PERCENT) {
536: *rx = a->a_rx_rate.r_total;
537: *tx = a->a_tx_rate.r_total;
538: } else {
539: *rx = __calc_usage(a->a_rx_rate.r_rate, rxmax);
540: *tx = __calc_usage(a->a_tx_rate.r_rate, txmax);
541: }
542: }
543:
544: static void calc_counter_rate(struct attr *a, struct rate *rate,
545: timestamp_t *ts)
546: {
547: uint64_t delta, prev_total;
548: float diff, old_rate;
549:
550: if (rate->r_current < rate->r_prev) {
551: /* Overflow detected */
552: if (a->a_flags & ATTR_IGNORE_OVERFLOWS)
553: delta = rate->r_current;
554: else {
555: if (a->a_flags & ATTR_TRUE_64BIT)
556: delta = 0xFFFFFFFFFFFFFFFFULL - rate->r_prev;
557: else
558: delta = 0xFFFFFFFFULL - rate->r_prev;
559:
560: delta += rate->r_current + 1;
561: }
562: } else
563: delta = rate->r_current - rate->r_prev;
564:
565: prev_total = rate->r_total;
566: rate->r_total += delta;
567: rate->r_prev = rate->r_current;
568:
569: if (!prev_total) {
570: /*
571: * No previous records exists, reset time to now to
572: * avoid doing unnecessary calculation, this behaviour
573: * continues as long as the counter stays 0.
574: */
575: goto out;
576: }
577:
578: diff = timestamp_diff(&rate->r_last_calc, ts);
579: if (diff < (cfg_rate_interval - cfg_rate_variance))
580: return;
581:
582: old_rate = rate->r_rate;
583:
584: if (rate->r_total < prev_total) {
585: /* overflow */
586: delta = 0xFFFFFFFFFFFFFFFFULL - prev_total;
587: delta += rate->r_total + 1;
588: } else
589: delta = rate->r_total - prev_total;
590:
591: rate->r_rate = delta / diff;
592:
593: if (old_rate)
594: rate->r_rate = ((rate->r_rate * 3.0f) + old_rate) / 4.0f;
595:
596: out:
597: copy_timestamp(&rate->r_last_calc, ts);
598: }
599:
600: static void calc_rate_total(struct attr *a, struct rate *rate, timestamp_t *ts)
601: {
602: rate->r_prev = rate->r_rate = rate->r_total = rate->r_current;
603: copy_timestamp(&rate->r_last_calc, ts);
604: }
605:
606: void attr_notify_update(struct attr *a, timestamp_t *ts)
607: {
608: switch (a->a_def->ad_type) {
609: case ATTR_TYPE_RATE:
610: case ATTR_TYPE_PERCENT:
611: calc_rate_total(a, &a->a_rx_rate, ts);
612: calc_rate_total(a, &a->a_tx_rate, ts);
613: break;
614:
615: case ATTR_TYPE_COUNTER:
616: calc_counter_rate(a, &a->a_rx_rate, ts);
617: calc_counter_rate(a, &a->a_tx_rate, ts);
618: break;
619: default:
620: DBG("Attribute update of unknown type");
621: break;
622: }
623:
624: if (a->a_flags & ATTR_DOING_HISTORY) {
625: struct history *h;
626:
627: DBG("Updating history of attribute %d (\"%s\")", a->a_def->ad_id, a->a_def->ad_name);
628:
629: list_for_each_entry(h, &a->a_history_list, h_list)
630: history_update(a, h, ts);
1.1.1.2 ! misho 631: }
! 632: }
! 633:
! 634: void attr_reset_counter(struct attr *a)
! 635: {
! 636: if (a->a_def->ad_type == ATTR_TYPE_COUNTER) {
! 637: a->a_rx_rate.r_reset = a->a_rx_rate.r_total;
! 638: a->a_tx_rate.r_reset = a->a_tx_rate.r_total;
1.1 misho 639: }
640: }
641:
642: static void __exit attr_exit(void)
643: {
644: struct attr_def *ad, *n;
645:
646: list_for_each_entry_safe(ad, n, &attr_def_list, ad_list)
647: attr_def_free(ad);
648: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>