Annotation of embedaddon/bmon/src/history.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * history.c           History Management
                      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/history.h>
                     29: #include <bmon/utils.h>
                     30: 
                     31: static LIST_HEAD(def_list);
                     32: 
                     33: static struct history_def *current_history;
                     34: 
                     35: struct history_def *history_def_lookup(const char *name)
                     36: {
                     37:        struct history_def *def;
                     38: 
                     39:        list_for_each_entry(def, &def_list, hd_list)
                     40:                if (!strcmp(def->hd_name, name))
                     41:                    return def;
                     42: 
                     43:        return NULL;
                     44: }
                     45: 
                     46: struct history_def *history_def_alloc(const char *name)
                     47: {
                     48:        struct history_def *def;
                     49: 
                     50:        if ((def = history_def_lookup(name)))
                     51:                return def;
                     52: 
                     53:        def = xcalloc(1, sizeof(*def));
                     54:        def->hd_name = strdup(name);
                     55: 
                     56:        list_add_tail(&def->hd_list, &def_list);
                     57: 
                     58:        DBG("New history definition %s", name);
                     59: 
                     60:        return def;
                     61: }
                     62: 
                     63: static void history_def_free(struct history_def *def)
                     64: {
                     65:        if (!def)
                     66:                return;
                     67: 
                     68:        xfree(def->hd_name);
                     69:        xfree(def);
                     70: }
                     71: 
                     72: static void *history_alloc_data(struct history_def *def)
                     73: {
                     74:        return xcalloc(def->hd_size, def->hd_type);
                     75: }
                     76: 
                     77: static void history_store_data(struct history *h, struct history_store *hs,
                     78:                               uint64_t total, float diff)
                     79: {
                     80:        uint64_t delta;
                     81: 
                     82:        if (!hs->hs_data) {
                     83:                if (total == HISTORY_UNKNOWN)
                     84:                        return;
                     85: 
                     86:                hs->hs_data = history_alloc_data(h->h_definition);
                     87:        }
                     88: 
                     89:        if (total == HISTORY_UNKNOWN)
                     90:                delta = HISTORY_UNKNOWN;
                     91:        else {
                     92:                delta = (total - hs->hs_prev_total);
                     93: 
                     94:                if (delta > 0)
                     95:                        delta /= diff;
                     96:                hs->hs_prev_total = total;
                     97:        }
                     98: 
                     99:        switch (h->h_definition->hd_type) {
                    100:        case HISTORY_TYPE_8:
                    101:                ((uint8_t *) hs->hs_data)[h->h_index] = (uint8_t) delta;
                    102:                break;
                    103:        
                    104:        case HISTORY_TYPE_16:
                    105:                ((uint16_t *) hs->hs_data)[h->h_index] = (uint16_t) delta;
                    106:                break;
                    107: 
                    108:        case HISTORY_TYPE_32:
                    109:                ((uint32_t *) hs->hs_data)[h->h_index] = (uint32_t) delta;
                    110:                break;
                    111: 
                    112:        case HISTORY_TYPE_64:
                    113:                ((uint64_t *) hs->hs_data)[h->h_index] = (uint64_t) delta;
                    114:                break;
                    115: 
                    116:        default:
                    117:                BUG();
                    118:        }
                    119: }
                    120: 
                    121: static inline void inc_history_index(struct history *h)
                    122: {
                    123:        if (h->h_index < (h->h_definition->hd_size - 1))
                    124:                h->h_index++;
                    125:        else
                    126:                h->h_index = 0;
                    127: }
                    128: 
                    129: uint64_t history_data(struct history *h, struct history_store *hs, int index)
                    130: {
                    131:        switch (h->h_definition->hd_type) {
                    132:        case HISTORY_TYPE_8: {
                    133:                uint8_t v = ((uint8_t *) hs->hs_data)[index];
                    134:                return (v == (uint8_t) -1) ? HISTORY_UNKNOWN : v;
                    135:        }
                    136:        
                    137:        case HISTORY_TYPE_16: {
                    138:                uint16_t v = ((uint16_t *) hs->hs_data)[index];
                    139:                return (v == (uint16_t) -1) ? HISTORY_UNKNOWN : v;
                    140:        }
                    141:  
                    142:        case HISTORY_TYPE_32: {
                    143:                uint32_t v = ((uint32_t *) hs->hs_data)[index];
                    144:                return (v == (uint32_t) -1) ? HISTORY_UNKNOWN : v;
                    145:        }
                    146: 
                    147:        case HISTORY_TYPE_64: {
                    148:                uint64_t v = ((uint64_t *) hs->hs_data)[index];
                    149:                return (v == (uint64_t) -1) ? HISTORY_UNKNOWN : v;
                    150:        }
                    151: 
                    152:        default:
                    153:                BUG();
                    154:        }
                    155: }
                    156: 
                    157: void history_update(struct attr *a, struct history *h, timestamp_t *ts)
                    158: {
                    159:        struct history_def *def = h->h_definition;
                    160:        float timediff;
                    161: 
                    162:        if (h->h_last_update.tv_sec)
                    163:                timediff = timestamp_diff(&h->h_last_update, ts);
                    164:        else {
                    165:                timediff = 0.0f; /* initial history update */
                    166: 
                    167:                /* Need a delta when working with counters */
                    168:                if (a->a_def->ad_type == ATTR_TYPE_COUNTER)
                    169:                        goto update_prev_total;
                    170:        }
                    171: 
                    172:        /*
                    173:         * A read interval greater than the desired history interval
                    174:         * can't possibly result in anything useful. Discard it and
                    175:         * mark history data as invalid. The user has to adjust the
                    176:         * read interval.
                    177:         */
                    178:        if (cfg_read_interval > def->hd_interval)
                    179:                goto discard;
                    180: 
                    181:        /*
                    182:         * If the history interval matches the read interval it makes
                    183:         * sense to update upon every read. The reader timing already
                    184:         * took care of being as close as possible to the desired
                    185:         * interval.
                    186:         */
                    187:        if (cfg_read_interval == def->hd_interval)
                    188:                goto update;
                    189: 
                    190:        if (timediff > h->h_max_interval)
                    191:                goto discard;
                    192: 
                    193:        if (timediff < h->h_min_interval)
                    194:                return;
                    195: 
                    196: update:
                    197:        history_store_data(h, &h->h_rx, a->a_rx_rate.r_total, timediff);
                    198:        history_store_data(h, &h->h_tx, a->a_tx_rate.r_total, timediff);
                    199:        inc_history_index(h);
                    200: 
                    201:        goto update_ts;
                    202: 
                    203: discard:
                    204:        while(timediff >= (def->hd_interval / 2)) {
                    205:                history_store_data(h, &h->h_rx, HISTORY_UNKNOWN, 0.0f);
                    206:                history_store_data(h, &h->h_tx, HISTORY_UNKNOWN, 0.0f);
                    207: 
                    208:                inc_history_index(h);
                    209:                timediff -= def->hd_interval;
                    210:        }
                    211: 
                    212: update_prev_total:
                    213:        h->h_rx.hs_prev_total = a->a_rx_rate.r_total;
                    214:        h->h_tx.hs_prev_total = a->a_tx_rate.r_total;
                    215: 
                    216: update_ts:
                    217:        copy_timestamp(&h->h_last_update, ts);
                    218: }
                    219: 
                    220: struct history *history_alloc(struct history_def *def)
                    221: {
                    222:        struct history *h;
                    223: 
                    224:        h  = xcalloc(1, sizeof(*h));
                    225: 
                    226:        init_list_head(&h->h_list);
                    227: 
                    228:        h->h_definition = def;
                    229: 
                    230:        h->h_min_interval = (def->hd_interval - (cfg_read_interval / 2.0f));
                    231:        h->h_max_interval = (def->hd_interval / cfg_history_variance);
                    232: 
                    233:        return h;
                    234: }
                    235: 
                    236: void history_free(struct history *h)
                    237: {
                    238:        if (!h)
                    239:                return;
                    240: 
                    241:        xfree(h->h_rx.hs_data);
                    242:        xfree(h->h_tx.hs_data);
                    243: 
                    244:        list_del(&h->h_list);
                    245: 
                    246:        xfree(h);
                    247: }
                    248: 
                    249: void history_attach(struct attr *attr)
                    250: {
                    251:        struct history_def *def;
                    252:        struct history *h;
                    253: 
                    254:        list_for_each_entry(def, &def_list, hd_list) {
                    255:                h = history_alloc(def);
                    256:                list_add_tail(&h->h_list, &attr->a_history_list);
                    257:        }
                    258: }
                    259: 
                    260: struct history_def *history_select_first(void)
                    261: {
                    262:        if (list_empty(&def_list))
                    263:                current_history = NULL;
                    264:        else
                    265:                current_history = list_first_entry(&def_list,
                    266:                                         struct history_def, hd_list);
                    267: 
                    268:        return current_history;
                    269: }
                    270: 
                    271: struct history_def *history_select_last(void)
                    272: {
                    273:        if (list_empty(&def_list))
                    274:                current_history = NULL;
                    275:        else
                    276:                current_history = list_entry(def_list.prev,
                    277:                                        struct history_def, hd_list);
                    278: 
                    279:        return current_history;
                    280: }
                    281: 
                    282: struct history_def *history_select_next(void)
                    283: {
                    284:        if (current_history && current_history->hd_list.next != &def_list) {
                    285:                current_history = list_entry(current_history->hd_list.next,
                    286:                                        struct history_def, hd_list);
                    287:                return current_history;
                    288:        }
                    289: 
                    290:        return history_select_first();
                    291: }
                    292: 
                    293: struct history_def *history_select_prev(void)
                    294: {
                    295:        if (current_history && current_history->hd_list.prev != &def_list) {
                    296:                current_history = list_entry(current_history->hd_list.prev,
                    297:                                        struct history_def, hd_list);
                    298:                return current_history;
                    299:        }
                    300: 
                    301:        return history_select_last();
                    302: }
                    303: 
                    304: struct history_def *history_current(void)
                    305: {
                    306:        if (!current_history)
                    307:                current_history = history_select_first();
                    308: 
                    309:        return current_history;
                    310: }
                    311: 
                    312: static void __exit history_exit(void)
                    313: {
                    314:        struct history_def *def, *n;
                    315: 
                    316:        list_for_each_entry_safe(def, n, &def_list, hd_list)
                    317:                history_def_free(def);
                    318: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>