Annotation of embedaddon/bmon/src/item.c, revision 1.1
1.1 ! misho 1: /*
! 2: * item.c Item Management
! 3: *
! 4: * Copyright (c) 2001-2004 Thomas Graf <tgraf@suug.ch>
! 5: *
! 6: * Permission is hereby granted, free of charge, to any person obtaining a
! 7: * copy of this software and associated documentation files (the "Software"),
! 8: * to deal in the Software without restriction, including without limitation
! 9: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
! 10: * and/or sell copies of the Software, and to permit persons to whom the
! 11: * Software is furnished to do so, subject to the following conditions:
! 12: *
! 13: * The above copyright notice and this permission notice shall be included
! 14: * in all copies or substantial portions of the Software.
! 15: *
! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
! 17: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
! 21: * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
! 22: * DEALINGS IN THE SOFTWARE.
! 23: */
! 24:
! 25: #include <bmon/bmon.h>
! 26: #include <bmon/node.h>
! 27: #include <bmon/conf.h>
! 28: #include <bmon/item.h>
! 29: #include <bmon/itemtab.h>
! 30: #include <bmon/input.h>
! 31: #include <bmon/graph.h>
! 32: #include <bmon/utils.h>
! 33:
! 34: #define MAX_POLICY 255
! 35: #define SECOND 1.0f
! 36: #define MINUTE 60.0f
! 37: #define HOUR 3600.0f
! 38: #define DAY 86400.0f
! 39:
! 40: static char * allowed_items[MAX_POLICY];
! 41: static char * denied_items[MAX_POLICY];
! 42: static char * allowed_attrs[MAX_POLICY];
! 43: static char * denied_attrs[MAX_POLICY];
! 44: static int allow_all_attrs;
! 45:
! 46: static inline uint8_t attr_hash(int type)
! 47: {
! 48: return (type & 0xFF) % ATTR_HASH_MAX;
! 49: }
! 50:
! 51: stat_attr_t *lookup_attr(item_t *it, int type)
! 52: {
! 53: stat_attr_t *a;
! 54: uint8_t h = attr_hash(type);
! 55:
! 56: for (a = it->i_attrs[h]; a; a = a->a_next)
! 57: if (a->a_type == type)
! 58: return a;
! 59: return NULL;
! 60: }
! 61:
! 62: b_cnt_t attr_get_rx(stat_attr_t *a)
! 63: {
! 64: #ifndef DISABLE_OVERFLOW_WORKAROUND
! 65: return (a->a_rx.r_overflows * OVERFLOW_LIMIT) + a->a_rx.r_total;
! 66: #else
! 67: return a->a_rx.r_total;
! 68: #endif
! 69: }
! 70:
! 71: rate_cnt_t attr_get_rx_rate(stat_attr_t *a)
! 72: {
! 73: return a->a_rx.r_tps;
! 74: }
! 75:
! 76: b_cnt_t attr_get_tx(stat_attr_t *a)
! 77: {
! 78: #ifndef DISABLE_OVERFLOW_WORKAROUND
! 79: return (a->a_tx.r_overflows * OVERFLOW_LIMIT) + a->a_tx.r_total;
! 80: #else
! 81: return a->a_tx.r_total;
! 82: #endif
! 83: }
! 84:
! 85: rate_cnt_t attr_get_tx_rate(stat_attr_t *a)
! 86: {
! 87: return a->a_tx.r_tps;
! 88: }
! 89: void foreach_attr(item_t *i, void (*cb)(stat_attr_t *, void *), void *arg)
! 90: {
! 91: int m;
! 92:
! 93: for (m = 0; m < ATTR_HASH_MAX; m++) {
! 94: stat_attr_t *a;
! 95: for (a = i->i_attrs[m]; a; a = a->a_next)
! 96: cb(a, arg);
! 97: }
! 98: }
! 99:
! 100: static struct attr_type attr_types[] = {
! 101: #define IGNORE_OVERFLOWS 1
! 102: #define IS_RATE 2
! 103: #define __A(_I, _N, _D, _U, _F) { .id = _I, .name = _N, .desc = _D, .flags = _F, .unit = _U }
! 104: __A(BYTES, "bytes", "Bytes", U_BYTES, 0),
! 105: __A(PACKETS, "packets", "Packets", U_NUMBER, 0),
! 106: __A(ERRORS, "errors", "Errors", U_NUMBER, 0),
! 107: __A(DROP, "drop", "Dropped", U_NUMBER, 0),
! 108: __A(FIFO, "fifo", "FIFO Err", U_NUMBER, 0),
! 109: __A(FRAME, "frame", "Frame Err", U_NUMBER, 0),
! 110: __A(COMPRESSED, "compressed", "Compressed", U_NUMBER, 0),
! 111: __A(MULTICAST, "multicast", "Multicast", U_NUMBER, 0),
! 112: __A(BROADCAST, "broadcast", "Broadcast", U_NUMBER, 0),
! 113: __A(LENGTH_ERRORS, "len_err", "Length Err", U_NUMBER, 0),
! 114: __A(OVER_ERRORS, "over_err", "Over Err", U_NUMBER, 0),
! 115: __A(CRC_ERRORS, "crc_err", "CRC Err", U_NUMBER, 0),
! 116: __A(MISSED_ERRORS, "miss_err", "Missed Err", U_NUMBER, 0),
! 117: __A(ABORTED_ERRORS, "abort_err", "Aborted Err", U_NUMBER, 0),
! 118: __A(CARRIER_ERRORS, "carrier_err", "Carrier Err", U_NUMBER, 0),
! 119: __A(HEARTBEAT_ERRORS, "hbeat_err", "HBeat Err", U_NUMBER, 0),
! 120: __A(WINDOW_ERRORS, "win_err", "Window Err", U_NUMBER, 0),
! 121: __A(COLLISIONS, "collisions", "Collisions", U_NUMBER, 0),
! 122: __A(OVERLIMITS, "overlimits", "Overlimits", U_NUMBER, 0),
! 123: __A(BPS, "bps", "Bits/s", U_BYTES, IGNORE_OVERFLOWS | IS_RATE),
! 124: __A(PPS, "pps", "Packets/s", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
! 125: __A(QLEN, "qlen", "Queue Len", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
! 126: __A(BACKLOG, "backlog", "Backlog", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
! 127: __A(REQUEUES, "requeues", "Requeues", U_NUMBER, 0)
! 128: #undef __A
! 129: };
! 130:
! 131: int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
! 132: {
! 133: int i, ret;
! 134:
! 135: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++) {
! 136: ret = cb(&attr_types[i], arg);
! 137: if (ret < 0)
! 138: return ret;
! 139: }
! 140:
! 141: return 0;
! 142: }
! 143:
! 144: const char * type2name(int type)
! 145: {
! 146: int i;
! 147:
! 148: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
! 149: if (attr_types[i].id == type)
! 150: return attr_types[i].name;
! 151:
! 152: return NULL;
! 153: }
! 154:
! 155: int name2type(const char *name)
! 156: {
! 157: int i;
! 158:
! 159: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
! 160: if (!strcasecmp(attr_types[i].name, name))
! 161: return attr_types[i].id;
! 162:
! 163: return INT_MAX;
! 164: }
! 165:
! 166: const char * type2desc(int type)
! 167: {
! 168: int i;
! 169: static char str[256];
! 170:
! 171: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
! 172: if (attr_types[i].id == type)
! 173: return attr_types[i].desc;
! 174:
! 175: snprintf(str, sizeof(str), "unknown (%d)", type);
! 176: return str;
! 177: }
! 178:
! 179: int attr_ignore_overflows(int type)
! 180: {
! 181: int i;
! 182:
! 183: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
! 184: if (attr_types[i].id == type &&
! 185: attr_types[i].flags & IGNORE_OVERFLOWS)
! 186: return 1;
! 187:
! 188: return 0;
! 189: }
! 190:
! 191: int attr_is_rate(int type)
! 192: {
! 193: int i;
! 194:
! 195: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
! 196: if (attr_types[i].id == type &&
! 197: attr_types[i].flags & IS_RATE)
! 198: return 1;
! 199:
! 200: return 0;
! 201: }
! 202:
! 203: int attr_unit(int type)
! 204: {
! 205: int i;
! 206:
! 207: for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
! 208: if (attr_types[i].id == type)
! 209: return attr_types[i].unit;
! 210:
! 211: return 0;
! 212: }
! 213:
! 214: static int match_mask(const char *mask, const char *str)
! 215: {
! 216: int i, n;
! 217: char c;
! 218:
! 219: if (!mask || !str)
! 220: return 0;
! 221:
! 222: for (i = 0, n = 0; mask[i] != '\0'; i++, n++) {
! 223: if (mask[i] == '*') {
! 224: c = tolower(mask[i+1]);
! 225:
! 226: if (c == '\0')
! 227: return 1; /* nothing after wildcard, matches in any case */
! 228:
! 229: /*look for c in str, c is the character after the wildcard */
! 230: for (; tolower(str[n]) != c; n++)
! 231: if (str[n] == '\0')
! 232: return 0; /* character after wildcard was not found */
! 233:
! 234: n--;
! 235: } else if (tolower(mask[i]) != tolower(str[n]))
! 236: return 0;
! 237: }
! 238:
! 239: return str[n] == '\0' ? 1 : 0;
! 240: }
! 241:
! 242: static int item_allowed(const char *name)
! 243: {
! 244: int n;
! 245:
! 246: if (!allowed_items[0] && !denied_items[0])
! 247: return 1;
! 248:
! 249: if (!allowed_items[0]) {
! 250: for (n = 0; n < MAX_POLICY && denied_items[n]; n++)
! 251: if (match_mask(denied_items[n], name))
! 252: return 0;
! 253:
! 254: return 1;
! 255: }
! 256:
! 257: for (n = 0; n < MAX_POLICY && denied_items[n]; n++)
! 258: if (match_mask(denied_items[n], name))
! 259: return 0;
! 260:
! 261: for (n=0; n < MAX_POLICY && allowed_items[n]; n++)
! 262: if (match_mask(allowed_items[n], name))
! 263: return 1;
! 264:
! 265: return 0;
! 266: }
! 267:
! 268: void item_parse_policy(const char *policy)
! 269: {
! 270: static int set = 0;
! 271: int i, a = 0, d = 0, f = 0;
! 272: char *p, *s;
! 273:
! 274: if (set)
! 275: return;
! 276: set = 1;
! 277:
! 278: s = strdup(policy);
! 279:
! 280: for (i = 0, p = s; ; i++) {
! 281: if (s[i] == ',' || s[i] == '\0') {
! 282:
! 283: f = s[i] == '\0' ? 1 : 0;
! 284: s[i] = '\0';
! 285:
! 286: if ('!' == *p) {
! 287: if (d > (MAX_POLICY - 1))
! 288: break;
! 289: denied_items[d++] = strdup(++p);
! 290: } else {
! 291: if(a > (MAX_POLICY - 1))
! 292: break;
! 293: allowed_items[a++] = strdup(p);
! 294: }
! 295:
! 296: if (f)
! 297: break;
! 298:
! 299: p = &s[i+1];
! 300: }
! 301: }
! 302:
! 303: xfree(s);
! 304: }
! 305:
! 306: static inline int collect_history(int type)
! 307: {
! 308: int n;
! 309: const char *name = type2name(type);
! 310:
! 311: if (allow_all_attrs)
! 312: return 1;
! 313:
! 314: if (!allowed_attrs[0] && !denied_attrs[0]) {
! 315: if (!strcmp(name, "bytes") || !strcmp(name, "packets"))
! 316: return 1;
! 317: else
! 318: return 0;
! 319: }
! 320:
! 321: if (!allowed_attrs[0]) {
! 322: for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
! 323: if (!strcasecmp(denied_attrs[n], name))
! 324: return 0;
! 325: return 1;
! 326: }
! 327:
! 328: for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
! 329: if (!strcasecmp(denied_attrs[n], name))
! 330: return 0;
! 331:
! 332: for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
! 333: if (!strcasecmp(allowed_attrs[n], name))
! 334: return 1;
! 335:
! 336: return 0;
! 337: }
! 338:
! 339: void parse_attr_policy(const char *policy)
! 340: {
! 341: static int set = 0;
! 342: int i, a = 0, d = 0, f = 0;
! 343: char *p, *s;
! 344:
! 345: if (set)
! 346: return;
! 347: set = 1;
! 348:
! 349: if (!strcasecmp(policy, "all")) {
! 350: allow_all_attrs = 1;
! 351: return ;
! 352: }
! 353:
! 354: s = strdup(policy);
! 355:
! 356: for (i = 0, p = s; ; i++) {
! 357: if (s[i] == ',' || s[i] == '\0') {
! 358:
! 359: f = s[i] == '\0' ? 1 : 0;
! 360: s[i] = '\0';
! 361:
! 362: if ('!' == *p) {
! 363: if (d > (MAX_POLICY - 1))
! 364: break;
! 365: denied_attrs[d++] = strdup(++p);
! 366: } else {
! 367: if(a > (MAX_POLICY - 1))
! 368: break;
! 369: allowed_attrs[a++] = strdup(p);
! 370: }
! 371:
! 372: if (f)
! 373: break;
! 374:
! 375: p = &s[i+1];
! 376: }
! 377: }
! 378:
! 379: xfree(s);
! 380: }
! 381:
! 382: item_t * lookup_item(node_t *node, const char *name, uint32_t handle,
! 383: item_t *parent)
! 384: {
! 385: int i;
! 386:
! 387: if (NULL == node)
! 388: BUG();
! 389:
! 390: if (NULL == node->n_items) {
! 391: node->n_nitems = 32;
! 392: node->n_items = xcalloc(node->n_nitems, sizeof(item_t));
! 393: }
! 394:
! 395: for (i = 0; i < node->n_nitems; i++)
! 396: if (!strcmp(name, node->n_items[i].i_name) &&
! 397: node->n_items[i].i_handle == handle &&
! 398: node->n_items[i].i_parent == (parent ? parent->i_index : 0))
! 399: return !(node->n_items[i].i_flags & ITEM_FLAG_UPDATED) ?
! 400: &node->n_items[i] : NULL;
! 401:
! 402: if (!handle && !item_allowed(name))
! 403: return NULL;
! 404:
! 405: for (i = 0; i < node->n_nitems; i++)
! 406: if (node->n_items[i].i_name[0] == '\0')
! 407: break;
! 408:
! 409: if (i >= node->n_nitems) {
! 410: int oldsize = node->n_nitems;
! 411: node->n_nitems += 32;
! 412: node->n_items = xrealloc(node->n_items, node->n_nitems * sizeof(item_t));
! 413: memset(node->n_items + oldsize, 0, (node->n_nitems - oldsize) * sizeof(item_t));
! 414: }
! 415:
! 416: memset(&node->n_items[i], 0, sizeof(node->n_items[i]));
! 417: strncpy(node->n_items[i].i_name, name, sizeof(node->n_items[i].i_name) - 1);
! 418: node->n_items[i].i_handle = handle;
! 419: node->n_items[i].i_parent = parent ? parent->i_index : 0;
! 420: node->n_items[i].i_index = i;
! 421: node->n_items[i].i_node = node;
! 422: node->n_items[i].i_lifetime = get_lifetime();
! 423:
! 424: if (!node->n_from)
! 425: node->n_items[i].i_flags |= ITEM_FLAG_LOCAL;
! 426:
! 427: {
! 428: struct it_item *tab = lookup_tab(&node->n_items[i]);
! 429:
! 430: if (tab && tab->ii_desc)
! 431: node->n_items[i].i_desc = tab->ii_desc;
! 432: }
! 433:
! 434: if (parent)
! 435: parent->i_flags |= ITEM_FLAG_HAS_CHILDS;
! 436:
! 437: return &node->n_items[i];
! 438: }
! 439:
! 440: void foreach_child(node_t *node, item_t *parent, void (*cb)(item_t *, void *),
! 441: void *arg)
! 442: {
! 443: int i;
! 444:
! 445: for (i = 0; i < node->n_nitems; i++)
! 446: if (node->n_items[i].i_parent == parent->i_index &&
! 447: node->n_items[i].i_flags & ITEM_FLAG_IS_CHILD)
! 448: cb(&node->n_items[i], arg);
! 449: }
! 450:
! 451: void reset_item(item_t *i)
! 452: {
! 453: i->i_flags &= ~ITEM_FLAG_UPDATED;
! 454: }
! 455:
! 456: void remove_unused_items(item_t *i)
! 457: {
! 458: if (--(i->i_lifetime) <= 0) {
! 459: int m;
! 460: for (m = 0; m < ATTR_HASH_MAX; m++) {
! 461: stat_attr_t *a, *next;
! 462: for (a = i->i_attrs[m]; a; a = next) {
! 463: next = a->a_next;
! 464: free(a);
! 465: }
! 466: }
! 467: if (!(i->i_flags & ITEM_FLAG_LOCAL)) {
! 468: if (i->i_desc)
! 469: free(i->i_desc);
! 470: }
! 471: memset(i, 0, sizeof(item_t));
! 472: }
! 473: }
! 474:
! 475: static void calc_rate(rate_t *rate, timestamp_t *ts, int ignore_overflows)
! 476: {
! 477: float diff;
! 478:
! 479: if (!rate->r_prev_total) {
! 480: rate->r_prev_total = rate->r_total;
! 481: COPY_TS(&rate->r_last_update, ts);
! 482: return;
! 483: }
! 484:
! 485: diff = time_diff(&rate->r_last_update, ts);
! 486:
! 487: if (diff >= get_rate_interval()) {
! 488: if (rate->r_total) {
! 489: rate_cnt_t old_rate;
! 490:
! 491: b_cnt_t t = (rate->r_total - rate->r_prev_total);
! 492: old_rate = rate->r_tps;
! 493:
! 494: #ifndef DISABLE_OVERFLOW_WORKAROUND
! 495: /* HACK:
! 496: *
! 497: * Workaround for counter overflow, all input methods
! 498: * except kstat in 64bit mode use a 32bit counter which
! 499: * tends to overflow. We can work around the problem
! 500: * when assuming that there will be no scenario with
! 501: * 4GiB/s and no more than 1 overflow per second.
! 502: */
! 503: if (t >= OVERFLOW_LIMIT &&
! 504: !rate->r_is64bit &&
! 505: !ignore_overflows) {
! 506: rate->r_tps = OVERFLOW_LIMIT -
! 507: (rate->r_prev_total - rate->r_total);
! 508: rate->r_overflows++;
! 509: } else
! 510: #endif
! 511: rate->r_tps = (rate_cnt_t) t;
! 512:
! 513: rate->r_tps /= diff;
! 514: rate->r_tps = ((rate->r_tps * 3) + old_rate) / 4;
! 515: rate->r_prev_total = rate->r_total;
! 516: }
! 517:
! 518: COPY_TS(&rate->r_last_update, ts);
! 519: }
! 520: }
! 521:
! 522: static inline b_cnt_t get_real_total(rate_t *r, unsigned int prev_overflows,
! 523: b_cnt_t prev_total)
! 524: {
! 525: b_cnt_t res;
! 526: unsigned int new_overflows = (r->r_overflows - prev_overflows);
! 527:
! 528: #ifndef DISABLE_OVERFLOW_WORKAROUND
! 529: if (new_overflows)
! 530: res = (new_overflows * OVERFLOW_LIMIT) + r->r_total - prev_total;
! 531: else
! 532: #endif
! 533: res = r->r_total - prev_total;
! 534:
! 535: return res;
! 536: }
! 537:
! 538: static inline void update_history_data(hist_data_t *hd, rate_t *r,
! 539: int index, double diff)
! 540: {
! 541: double t;
! 542:
! 543: t = (double) get_real_total(r, hd->hd_overflows,
! 544: hd->hd_prev_total) / diff;
! 545: hd->hd_data[index] = (rate_cnt_t) t;
! 546: hd->hd_prev_total = r->r_total;
! 547: hd->hd_overflows = r->r_overflows;
! 548: }
! 549:
! 550: static void update_history_element(hist_elem_t *he, rate_t *rx, rate_t *tx,
! 551: timestamp_t *ts, float unit)
! 552: {
! 553: double diff = time_diff(&he->he_last_update, ts);
! 554:
! 555: if (!he->he_last_update.tv_sec)
! 556: diff = 0.0f;
! 557:
! 558: /* Do not updated histor for graphs with intervals
! 559: * less than the reading interval. */
! 560: if (get_read_interval() > unit)
! 561: goto discard;
! 562:
! 563: /* Discard outdated updates */
! 564: if (diff >= (unit + (get_hb_factor() * unit)))
! 565: goto discard;
! 566:
! 567: if (!he->he_last_update.tv_sec) {
! 568: he->he_rx.hd_prev_total = rx->r_total;
! 569: he->he_tx.hd_prev_total = tx->r_total;
! 570: } else if (get_read_interval() == unit) {
! 571: update_history_data(&he->he_rx, rx, he->he_index, 1.0f);
! 572: update_history_data(&he->he_tx, tx, he->he_index, 1.0f);
! 573: /* The timing code might do shorter intervals than requested to
! 574: * adjust previous intervals being too long */
! 575: } else if (diff >= ((1.0f - get_hb_factor()) * unit)) {
! 576: update_history_data(&he->he_rx, rx, he->he_index, diff);
! 577: update_history_data(&he->he_tx, tx, he->he_index, diff);
! 578: } else {
! 579: /* Silently discard and give it a chance to come back
! 580: * in time. */
! 581: return;
! 582: }
! 583:
! 584: if (he->he_index >= (HISTORY_SIZE - 1))
! 585: he->he_index = 0;
! 586: else
! 587: he->he_index++;
! 588:
! 589: COPY_TS(&he->he_last_update, ts);
! 590:
! 591: return;
! 592: discard:
! 593: while(diff > 0.0f) {
! 594: he->he_rx.hd_data[he->he_index] = UNK_DATA;
! 595: he->he_tx.hd_data[he->he_index] = UNK_DATA;
! 596:
! 597: if (he->he_index >= (HISTORY_SIZE - 1))
! 598: he->he_index = 0;
! 599: else
! 600: he->he_index++;
! 601:
! 602: diff -= unit;
! 603: }
! 604:
! 605: he->he_rx.hd_prev_total = rx->r_total;
! 606: he->he_tx.hd_prev_total = tx->r_total;
! 607:
! 608: he->he_rx.hd_overflows = rx->r_overflows;
! 609: he->he_tx.hd_overflows = tx->r_overflows;
! 610: COPY_TS(&he->he_last_update, ts);
! 611:
! 612: }
! 613:
! 614: static inline void update_history(history_t *hist, rate_t *rx, rate_t *tx,
! 615: timestamp_t *ts)
! 616: {
! 617: if (get_read_interval() != 1.0f)
! 618: update_history_element(&hist->h_read, rx, tx, ts,
! 619: get_read_interval());
! 620: update_history_element(&hist->h_sec, rx, tx, ts, SECOND);
! 621: update_history_element(&hist->h_min, rx, tx, ts, MINUTE);
! 622: update_history_element(&hist->h_hour, rx, tx, ts, HOUR);
! 623: update_history_element(&hist->h_day, rx, tx, ts, DAY);
! 624: }
! 625:
! 626: static void update_attr_hist(stat_attr_t *a, void *arg)
! 627: {
! 628: timestamp_t *ts = (timestamp_t *) arg;
! 629: int ign_of = a->a_flags & ATTR_FLAG_IGNORE_OVERFLOWS;
! 630:
! 631: if (ts == NULL)
! 632: ts = &rtiming.rt_last_read;
! 633:
! 634: if (a->a_flags & ATTR_FLAG_IS_RATE) {
! 635: a->a_rx.r_tps = a->a_rx.r_total;
! 636: a->a_tx.r_tps = a->a_tx.r_total;
! 637: } else {
! 638: calc_rate(&a->a_rx, ts, ign_of);
! 639: calc_rate(&a->a_tx, ts, ign_of);
! 640: }
! 641:
! 642: if (a->a_flags & ATTR_FLAG_HISTORY) {
! 643: stat_attr_hist_t *ah = (stat_attr_hist_t *) a;
! 644: update_history(&ah->a_hist, &ah->a_rx, &ah->a_tx, ts);
! 645: }
! 646: }
! 647:
! 648: void notify_update(item_t *i, timestamp_t *ts)
! 649: {
! 650: struct it_item *tab;
! 651: stat_attr_t *a;
! 652:
! 653: i->i_flags |= ITEM_FLAG_UPDATED;
! 654: foreach_attr(i, &update_attr_hist, ts);
! 655:
! 656: a = lookup_attr(i, i->i_major_attr);
! 657: tab = lookup_tab(i);
! 658:
! 659: if (tab && a) {
! 660: rate_cnt_t rx = attr_get_rx_rate(a);
! 661: rate_cnt_t tx = attr_get_tx_rate(a);
! 662:
! 663: if (tab->ii_rx_max) {
! 664: if (rx)
! 665: i->i_rx_usage = (100.0f / (tab->ii_rx_max / rx));
! 666: else
! 667: i->i_rx_usage = 0;
! 668: } else
! 669: i->i_rx_usage = -1;
! 670:
! 671: if (tab->ii_tx_max) {
! 672: if (tx)
! 673: i->i_tx_usage = (100.0f / (tab->ii_tx_max / tx));
! 674: else
! 675: i->i_tx_usage = 0;
! 676: } else
! 677: i->i_tx_usage = -1;
! 678: } else if (!i->i_node || !i->i_node->n_from) {
! 679: i->i_rx_usage = -1;
! 680: i->i_tx_usage = -1;
! 681: }
! 682: }
! 683:
! 684: void increase_lifetime(item_t *i, int l)
! 685: {
! 686: i->i_lifetime = l*get_lifetime();
! 687: }
! 688:
! 689: void update_attr(item_t *i, int type, b_cnt_t rx, b_cnt_t tx, int flags)
! 690: {
! 691: stat_attr_t *a;
! 692: uint8_t h = attr_hash(type);
! 693:
! 694: for (a = i->i_attrs[h]; a; a = a->a_next)
! 695: if (a->a_type == type)
! 696: goto found;
! 697:
! 698: if (collect_history(type)) {
! 699: a = xcalloc(1, sizeof(stat_attr_hist_t));
! 700: a->a_flags |= ATTR_FLAG_HISTORY;
! 701: } else
! 702: a = xcalloc(1, sizeof(stat_attr_t));
! 703:
! 704: a->a_type = type;
! 705: a->a_unit = attr_unit(a->a_type);
! 706: if (attr_ignore_overflows(a->a_type))
! 707: a->a_flags |= ATTR_FLAG_IGNORE_OVERFLOWS;
! 708: if (attr_is_rate(a->a_type))
! 709: a->a_flags |= ATTR_FLAG_IS_RATE;
! 710:
! 711: a->a_next = i->i_attrs[h];
! 712: i->i_attrs[h] = a;
! 713: i->i_nattrs++;
! 714:
! 715: found:
! 716: if (flags & IS64BIT)
! 717: a->a_rx.r_is64bit = a->a_tx.r_is64bit = 1;
! 718:
! 719: if (flags & RX_PROVIDED) {
! 720: a->a_rx.r_total = rx;
! 721: a->a_flags |= ATTR_FLAG_RX_ENABLED;
! 722: update_ts(&a->a_updated); /* XXX: use read ts */
! 723: }
! 724:
! 725: if (flags & TX_PROVIDED) {
! 726: a->a_tx.r_total = tx;
! 727: a->a_flags |= ATTR_FLAG_TX_ENABLED;
! 728: update_ts(&a->a_updated);
! 729: }
! 730: }
! 731:
! 732:
! 733: item_t * get_item(node_t *node, int index)
! 734: {
! 735: int i;
! 736:
! 737: for (i = 0; i < node->n_nitems; i++)
! 738: if (node->n_items[i].i_index == index)
! 739: return &node->n_items[i];
! 740: return NULL;
! 741: }
! 742:
! 743: stat_attr_t *current_attr(int graph)
! 744: {
! 745: int i, c;
! 746: item_t *it = get_current_item();
! 747: stat_attr_t *a;
! 748:
! 749: if (it == NULL)
! 750: return NULL;
! 751:
! 752: for (i = 0, c = 0; i < ATTR_HASH_MAX; i++)
! 753: for (a = it->i_attrs[i]; a; a = a->a_next, c++)
! 754: if (c == it->i_attr_sel[graph])
! 755: return a;
! 756:
! 757: return NULL;
! 758: }
! 759:
! 760: int first_attr(void)
! 761: {
! 762: int i, c;
! 763: stat_attr_t *a;
! 764: item_t *it = get_current_item();
! 765: if (it == NULL)
! 766: return EMPTY_LIST;
! 767:
! 768: for (i = 0, c = 0; i < ATTR_HASH_MAX; i++) {
! 769: for (a = it->i_attrs[i]; a; a = a->a_next) {
! 770: if (a->a_flags & ATTR_FLAG_HISTORY) {
! 771: it->i_attr_sel[it->i_graph_sel] = c;
! 772: return 0;
! 773: } else
! 774: c++;
! 775: }
! 776: }
! 777:
! 778: return EMPTY_LIST;
! 779: }
! 780:
! 781: int next_attr(void)
! 782: {
! 783: item_t *it = get_current_item();
! 784: if (it == NULL)
! 785: return EMPTY_LIST;
! 786:
! 787: if (it->i_attr_sel[it->i_graph_sel] >= (it->i_nattrs - 1))
! 788: return first_attr();
! 789: else {
! 790: stat_attr_t *a = current_attr(it->i_graph_sel);
! 791: int i, n = it->i_attr_sel[it->i_graph_sel] + 1;
! 792:
! 793: if (a) {
! 794: stat_attr_t *b = a->a_next;
! 795: i = attr_hash(a->a_type);
! 796: if (!b)
! 797: i++;
! 798: for (; i < ATTR_HASH_MAX; i++) {
! 799: for (a = b ? : it->i_attrs[i]; a; a = a->a_next) {
! 800: if (!(a->a_flags & ATTR_FLAG_HISTORY)) {
! 801: n++;
! 802: continue;
! 803: }
! 804: b = NULL;
! 805: it->i_attr_sel[it->i_graph_sel] = n;
! 806: return 0;
! 807: }
! 808: }
! 809: }
! 810:
! 811: return first_attr();
! 812: }
! 813:
! 814: return 0;
! 815: }
! 816:
! 817:
! 818: int set_graph_unit(int unit)
! 819: {
! 820: item_t *it = get_current_item();
! 821: if (it == NULL)
! 822: return EMPTY_LIST;
! 823:
! 824: it->i_unit[it->i_graph_sel] = unit;
! 825:
! 826: return 0;
! 827: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>