File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bmon / src / history.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jul 30 07:55:27 2014 UTC (10 years, 11 months ago) by misho
Branches: bmon, MAIN
CVS tags: v4_0p0, v3_3, HEAD
bmon 3.3

    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>