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