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>