Annotation of embedaddon/bmon/src/item.c, revision 1.1.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>