Annotation of embedaddon/bmon/src/attr.c, revision 1.1
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:
! 114: void attr_def_free(struct attr_def *def)
! 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:
! 527: void attr_calc_usage(struct attr *a, float *rx, float *tx,
! 528: uint64_t rxmax, uint64_t txmax)
! 529: {
! 530: if (a->a_def->ad_type == ATTR_TYPE_PERCENT) {
! 531: *rx = a->a_rx_rate.r_total;
! 532: *tx = a->a_tx_rate.r_total;
! 533: } else {
! 534: *rx = __calc_usage(a->a_rx_rate.r_rate, rxmax);
! 535: *tx = __calc_usage(a->a_tx_rate.r_rate, txmax);
! 536: }
! 537: }
! 538:
! 539: static void calc_counter_rate(struct attr *a, struct rate *rate,
! 540: timestamp_t *ts)
! 541: {
! 542: uint64_t delta, prev_total;
! 543: float diff, old_rate;
! 544:
! 545: if (rate->r_current < rate->r_prev) {
! 546: /* Overflow detected */
! 547: if (a->a_flags & ATTR_IGNORE_OVERFLOWS)
! 548: delta = rate->r_current;
! 549: else {
! 550: if (a->a_flags & ATTR_TRUE_64BIT)
! 551: delta = 0xFFFFFFFFFFFFFFFFULL - rate->r_prev;
! 552: else
! 553: delta = 0xFFFFFFFFULL - rate->r_prev;
! 554:
! 555: delta += rate->r_current + 1;
! 556: }
! 557: } else
! 558: delta = rate->r_current - rate->r_prev;
! 559:
! 560: prev_total = rate->r_total;
! 561: rate->r_total += delta;
! 562: rate->r_prev = rate->r_current;
! 563:
! 564: if (!prev_total) {
! 565: /*
! 566: * No previous records exists, reset time to now to
! 567: * avoid doing unnecessary calculation, this behaviour
! 568: * continues as long as the counter stays 0.
! 569: */
! 570: goto out;
! 571: }
! 572:
! 573: diff = timestamp_diff(&rate->r_last_calc, ts);
! 574: if (diff < (cfg_rate_interval - cfg_rate_variance))
! 575: return;
! 576:
! 577: old_rate = rate->r_rate;
! 578:
! 579: if (rate->r_total < prev_total) {
! 580: /* overflow */
! 581: delta = 0xFFFFFFFFFFFFFFFFULL - prev_total;
! 582: delta += rate->r_total + 1;
! 583: } else
! 584: delta = rate->r_total - prev_total;
! 585:
! 586: rate->r_rate = delta / diff;
! 587:
! 588: if (old_rate)
! 589: rate->r_rate = ((rate->r_rate * 3.0f) + old_rate) / 4.0f;
! 590:
! 591: out:
! 592: copy_timestamp(&rate->r_last_calc, ts);
! 593: }
! 594:
! 595: static void calc_rate_total(struct attr *a, struct rate *rate, timestamp_t *ts)
! 596: {
! 597: rate->r_prev = rate->r_rate = rate->r_total = rate->r_current;
! 598: copy_timestamp(&rate->r_last_calc, ts);
! 599: }
! 600:
! 601: void attr_notify_update(struct attr *a, timestamp_t *ts)
! 602: {
! 603: switch (a->a_def->ad_type) {
! 604: case ATTR_TYPE_RATE:
! 605: case ATTR_TYPE_PERCENT:
! 606: calc_rate_total(a, &a->a_rx_rate, ts);
! 607: calc_rate_total(a, &a->a_tx_rate, ts);
! 608: break;
! 609:
! 610: case ATTR_TYPE_COUNTER:
! 611: calc_counter_rate(a, &a->a_rx_rate, ts);
! 612: calc_counter_rate(a, &a->a_tx_rate, ts);
! 613: break;
! 614: default:
! 615: DBG("Attribute update of unknown type");
! 616: break;
! 617: }
! 618:
! 619: if (a->a_flags & ATTR_DOING_HISTORY) {
! 620: struct history *h;
! 621:
! 622: DBG("Updating history of attribute %d (\"%s\")", a->a_def->ad_id, a->a_def->ad_name);
! 623:
! 624: list_for_each_entry(h, &a->a_history_list, h_list)
! 625: history_update(a, h, ts);
! 626: }
! 627: }
! 628:
! 629: static void __exit attr_exit(void)
! 630: {
! 631: struct attr_def *ad, *n;
! 632:
! 633: list_for_each_entry_safe(ad, n, &attr_def_list, ad_list)
! 634: attr_def_free(ad);
! 635: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>