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