File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bmon / src / item.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:19:56 2012 UTC (13 years, 4 months ago) by misho
Branches: bmon, MAIN
CVS tags: v2_1_0p0, v2_1_0, HEAD
bmon

    1: /*
    2:  * item.c		Item Management
    3:  *
    4:  * Copyright (c) 2001-2004 Thomas Graf <tgraf@suug.ch>
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a
    7:  * copy of this software and associated documentation files (the "Software"),
    8:  * to deal in the Software without restriction, including without limitation
    9:  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   10:  * and/or sell copies of the Software, and to permit persons to whom the
   11:  * Software is furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included
   14:  * in all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   17:  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   21:  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   22:  * DEALINGS IN THE SOFTWARE.
   23:  */
   24: 
   25: #include <bmon/bmon.h>
   26: #include <bmon/node.h>
   27: #include <bmon/conf.h>
   28: #include <bmon/item.h>
   29: #include <bmon/itemtab.h>
   30: #include <bmon/input.h>
   31: #include <bmon/graph.h>
   32: #include <bmon/utils.h>
   33: 
   34: #define MAX_POLICY             255
   35: #define SECOND                 1.0f
   36: #define MINUTE                60.0f
   37: #define HOUR                3600.0f
   38: #define DAY                86400.0f
   39: 
   40: static char * allowed_items[MAX_POLICY];
   41: static char * denied_items[MAX_POLICY];
   42: static char * allowed_attrs[MAX_POLICY];
   43: static char * denied_attrs[MAX_POLICY];
   44: static int allow_all_attrs;
   45: 
   46: static inline uint8_t attr_hash(int type)
   47: {
   48: 	return (type & 0xFF) % ATTR_HASH_MAX;
   49: }
   50: 
   51: stat_attr_t *lookup_attr(item_t *it, int type)
   52: {
   53: 	stat_attr_t *a;
   54: 	uint8_t h = attr_hash(type);
   55: 	
   56: 	for (a = it->i_attrs[h]; a; a = a->a_next)
   57: 		if (a->a_type == type)
   58: 			return a;
   59: 	return NULL;
   60: }
   61: 
   62: b_cnt_t attr_get_rx(stat_attr_t *a)
   63: {
   64: #ifndef DISABLE_OVERFLOW_WORKAROUND
   65: 	return (a->a_rx.r_overflows * OVERFLOW_LIMIT) + a->a_rx.r_total;
   66: #else
   67: 	return a->a_rx.r_total;
   68: #endif
   69: }
   70: 
   71: rate_cnt_t attr_get_rx_rate(stat_attr_t *a)
   72: {
   73: 	return a->a_rx.r_tps;
   74: }
   75: 
   76: b_cnt_t attr_get_tx(stat_attr_t *a)
   77: {
   78: #ifndef DISABLE_OVERFLOW_WORKAROUND
   79: 	return (a->a_tx.r_overflows * OVERFLOW_LIMIT) + a->a_tx.r_total;
   80: #else
   81: 	return a->a_tx.r_total;
   82: #endif
   83: }
   84: 
   85: rate_cnt_t attr_get_tx_rate(stat_attr_t *a)
   86: {
   87: 	return a->a_tx.r_tps;
   88: }
   89: void foreach_attr(item_t *i, void (*cb)(stat_attr_t *, void *), void *arg)
   90: {
   91: 	int m;
   92: 
   93: 	for (m = 0; m < ATTR_HASH_MAX; m++) {
   94: 		stat_attr_t *a;
   95: 		for (a = i->i_attrs[m]; a; a = a->a_next)
   96: 			cb(a, arg);
   97: 	}
   98: }
   99: 
  100: static struct attr_type attr_types[] = {
  101: #define IGNORE_OVERFLOWS 1
  102: #define IS_RATE 2
  103: #define __A(_I, _N, _D, _U, _F) { .id = _I, .name = _N, .desc = _D, .flags = _F, .unit = _U }
  104: 	__A(BYTES, "bytes", "Bytes", U_BYTES, 0),
  105: 	__A(PACKETS, "packets", "Packets", U_NUMBER, 0),
  106: 	__A(ERRORS, "errors", "Errors", U_NUMBER, 0),
  107: 	__A(DROP, "drop", "Dropped", U_NUMBER, 0),
  108: 	__A(FIFO, "fifo", "FIFO Err", U_NUMBER, 0),
  109: 	__A(FRAME, "frame", "Frame Err", U_NUMBER, 0),
  110: 	__A(COMPRESSED, "compressed", "Compressed", U_NUMBER, 0),
  111: 	__A(MULTICAST, "multicast", "Multicast", U_NUMBER, 0),
  112: 	__A(BROADCAST, "broadcast", "Broadcast", U_NUMBER, 0),
  113: 	__A(LENGTH_ERRORS, "len_err", "Length Err", U_NUMBER, 0),
  114: 	__A(OVER_ERRORS, "over_err", "Over Err", U_NUMBER, 0),
  115: 	__A(CRC_ERRORS, "crc_err", "CRC Err", U_NUMBER, 0),
  116: 	__A(MISSED_ERRORS, "miss_err", "Missed Err", U_NUMBER, 0),
  117: 	__A(ABORTED_ERRORS, "abort_err", "Aborted Err", U_NUMBER, 0),
  118: 	__A(CARRIER_ERRORS, "carrier_err", "Carrier Err", U_NUMBER, 0),
  119: 	__A(HEARTBEAT_ERRORS, "hbeat_err", "HBeat Err", U_NUMBER, 0),
  120: 	__A(WINDOW_ERRORS, "win_err", "Window Err", U_NUMBER, 0),
  121: 	__A(COLLISIONS, "collisions", "Collisions", U_NUMBER, 0),
  122: 	__A(OVERLIMITS, "overlimits", "Overlimits", U_NUMBER, 0),
  123: 	__A(BPS, "bps", "Bits/s", U_BYTES, IGNORE_OVERFLOWS | IS_RATE),
  124: 	__A(PPS, "pps", "Packets/s", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
  125: 	__A(QLEN, "qlen", "Queue Len", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
  126: 	__A(BACKLOG, "backlog", "Backlog", U_NUMBER, IGNORE_OVERFLOWS | IS_RATE),
  127: 	__A(REQUEUES, "requeues", "Requeues", U_NUMBER, 0)
  128: #undef __A
  129: };
  130: 
  131: int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
  132: {
  133: 	int i, ret;
  134: 
  135: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++) {
  136: 		ret = cb(&attr_types[i], arg);
  137: 		if (ret < 0)
  138: 			return ret;
  139: 	}
  140: 
  141: 	return 0;
  142: }
  143: 
  144: const char * type2name(int type)
  145: {
  146: 	int i;
  147: 
  148: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
  149: 		if (attr_types[i].id == type)
  150: 			return attr_types[i].name;
  151: 
  152: 	return NULL;
  153: }
  154: 
  155: int name2type(const char *name)
  156: {
  157: 	int i;
  158: 
  159: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
  160: 		if (!strcasecmp(attr_types[i].name, name))
  161: 			return attr_types[i].id;
  162: 
  163: 	return INT_MAX;
  164: }
  165: 
  166: const char * type2desc(int type)
  167: {
  168: 	int i;
  169: 	static char str[256];
  170: 
  171: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
  172: 		if (attr_types[i].id == type)
  173: 			return attr_types[i].desc;
  174: 
  175: 	snprintf(str, sizeof(str), "unknown (%d)", type);
  176: 	return str;
  177: }
  178: 
  179: int attr_ignore_overflows(int type)
  180: {
  181: 	int i;
  182: 
  183: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
  184: 		if (attr_types[i].id == type &&
  185: 		    attr_types[i].flags & IGNORE_OVERFLOWS)
  186: 			return 1;
  187: 
  188: 	return 0;
  189: }
  190: 
  191: int attr_is_rate(int type)
  192: {
  193: 	int i;
  194: 
  195: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
  196: 		if (attr_types[i].id == type &&
  197: 		    attr_types[i].flags & IS_RATE)
  198: 			return 1;
  199: 
  200: 	return 0;
  201: }
  202: 
  203: int attr_unit(int type)
  204: {
  205: 	int i;
  206: 
  207: 	for (i = 0; i < sizeof(attr_types)/sizeof(attr_types[0]); i++)
  208: 		if (attr_types[i].id == type)
  209: 			return attr_types[i].unit;
  210: 
  211: 	return 0;
  212: }
  213: 
  214: static int match_mask(const char *mask, const char *str)
  215: {
  216: 	int i, n;
  217: 	char c;
  218: 
  219: 	if (!mask || !str)
  220: 		return 0;
  221: 	
  222: 	for (i = 0, n = 0; mask[i] != '\0'; i++, n++) {
  223: 		if (mask[i] == '*') {
  224: 			c = tolower(mask[i+1]);
  225: 			
  226: 			if (c == '\0')
  227: 				return 1; /* nothing after wildcard, matches in any case */
  228: 			
  229: 			/*look for c in str, c is the character after the wildcard */
  230: 			for (; tolower(str[n]) != c; n++)
  231: 				if (str[n] == '\0')
  232: 					return 0; /* character after wildcard was not found */
  233: 			
  234: 			n--;
  235: 		} else if (tolower(mask[i]) != tolower(str[n]))
  236: 			return 0;
  237: 	}
  238: 
  239: 	return str[n] == '\0' ? 1 : 0;
  240: }
  241: 
  242: static int item_allowed(const char *name)
  243: {
  244: 	int n;
  245: 	
  246: 	if (!allowed_items[0] && !denied_items[0])
  247: 		return 1;
  248: 
  249: 	if (!allowed_items[0]) {
  250: 		for (n = 0; n < MAX_POLICY && denied_items[n]; n++)
  251: 			if (match_mask(denied_items[n], name))
  252: 				return 0;
  253: 	
  254: 		return 1;
  255: 	}
  256: 
  257: 	for (n = 0; n < MAX_POLICY && denied_items[n]; n++)
  258: 		if (match_mask(denied_items[n], name))
  259: 			return 0;
  260: 	
  261: 	for (n=0; n < MAX_POLICY && allowed_items[n]; n++)
  262: 		if (match_mask(allowed_items[n], name))
  263: 			return 1;
  264: 
  265: 	return 0;
  266: }
  267: 
  268: void item_parse_policy(const char *policy)
  269: {
  270: 	static int set = 0;
  271: 	int i, a = 0, d = 0, f = 0;
  272: 	char *p, *s;
  273: 
  274: 	if (set)
  275: 		return;
  276: 	set = 1;
  277: 	
  278: 	s = strdup(policy);
  279: 	
  280: 	for (i = 0, p = s; ; i++) {
  281: 		if (s[i] == ',' || s[i] == '\0') {
  282: 
  283: 			f = s[i] == '\0' ? 1 : 0;
  284: 			s[i] = '\0';
  285: 			
  286: 			if ('!' == *p) {
  287: 				if (d > (MAX_POLICY - 1))
  288: 					break;
  289: 				denied_items[d++] = strdup(++p);
  290: 			} else {
  291: 				if(a > (MAX_POLICY - 1))
  292: 					break;
  293: 				allowed_items[a++] = strdup(p);
  294: 			}
  295: 			
  296: 			if (f)
  297: 				break;
  298: 			
  299: 			p = &s[i+1];
  300: 		}
  301: 	}
  302: 	
  303: 	xfree(s);
  304: }
  305: 
  306: static inline int collect_history(int type)
  307: {
  308: 	int n;
  309: 	const char *name = type2name(type);
  310: 
  311: 	if (allow_all_attrs)
  312: 		return 1;
  313: 
  314: 	if (!allowed_attrs[0] && !denied_attrs[0]) {
  315: 		if (!strcmp(name, "bytes") || !strcmp(name, "packets"))
  316: 			return 1;
  317: 		else
  318: 			return 0;
  319: 	}
  320: 
  321: 	if (!allowed_attrs[0]) {
  322: 		for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
  323: 			if (!strcasecmp(denied_attrs[n], name))
  324: 				return 0;
  325: 		return 1;
  326: 	}
  327: 
  328: 	for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
  329: 		if (!strcasecmp(denied_attrs[n], name))
  330: 			return 0;
  331: 	
  332: 	for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
  333: 		if (!strcasecmp(allowed_attrs[n], name))
  334: 			return 1;
  335: 
  336: 	return 0;
  337: }
  338: 
  339: void parse_attr_policy(const char *policy)
  340: {
  341: 	static int set = 0;
  342: 	int i, a = 0, d = 0, f = 0;
  343: 	char *p, *s;
  344: 
  345: 	if (set)
  346: 		return;
  347: 	set = 1;
  348: 
  349: 	if (!strcasecmp(policy, "all")) {
  350: 		allow_all_attrs = 1;
  351: 		return ;
  352: 	}
  353: 
  354: 	s = strdup(policy);
  355: 	
  356: 	for (i = 0, p = s; ; i++) {
  357: 		if (s[i] == ',' || s[i] == '\0') {
  358: 
  359: 			f = s[i] == '\0' ? 1 : 0;
  360: 			s[i] = '\0';
  361: 			
  362: 			if ('!' == *p) {
  363: 				if (d > (MAX_POLICY - 1))
  364: 					break;
  365: 				denied_attrs[d++] = strdup(++p);
  366: 			} else {
  367: 				if(a > (MAX_POLICY - 1))
  368: 					break;
  369: 				allowed_attrs[a++] = strdup(p);
  370: 			}
  371: 			
  372: 			if (f)
  373: 				break;
  374: 			
  375: 			p = &s[i+1];
  376: 		}
  377: 	}
  378: 	
  379: 	xfree(s);
  380: }
  381: 
  382: item_t * lookup_item(node_t *node, const char *name, uint32_t handle,
  383: 		     item_t *parent)
  384: {
  385: 	int i;
  386: 	
  387: 	if (NULL == node)
  388: 		BUG();
  389: 	
  390: 	if (NULL == node->n_items) {
  391: 		node->n_nitems = 32;
  392: 		node->n_items = xcalloc(node->n_nitems, sizeof(item_t));
  393: 	}
  394: 	
  395: 	for (i = 0; i < node->n_nitems; i++)
  396: 		if (!strcmp(name, node->n_items[i].i_name) &&
  397: 			node->n_items[i].i_handle == handle &&
  398: 			node->n_items[i].i_parent == (parent ? parent->i_index : 0))
  399: 			return !(node->n_items[i].i_flags & ITEM_FLAG_UPDATED) ?
  400: 				&node->n_items[i] : NULL;
  401: 	
  402: 	if (!handle && !item_allowed(name))
  403: 		return NULL;
  404: 	
  405: 	for (i = 0; i < node->n_nitems; i++)
  406: 		if (node->n_items[i].i_name[0] == '\0')
  407: 			break;
  408: 	
  409: 	if (i >= node->n_nitems) {
  410: 		int oldsize = node->n_nitems;
  411: 		node->n_nitems += 32;
  412: 		node->n_items = xrealloc(node->n_items, node->n_nitems * sizeof(item_t));
  413: 		memset(node->n_items + oldsize, 0, (node->n_nitems - oldsize) * sizeof(item_t));
  414: 	}
  415: 	
  416: 	memset(&node->n_items[i], 0, sizeof(node->n_items[i]));
  417: 	strncpy(node->n_items[i].i_name, name, sizeof(node->n_items[i].i_name) - 1);
  418: 	node->n_items[i].i_handle = handle;
  419: 	node->n_items[i].i_parent = parent ? parent->i_index : 0;
  420: 	node->n_items[i].i_index = i;
  421: 	node->n_items[i].i_node = node;
  422: 	node->n_items[i].i_lifetime = get_lifetime();
  423: 
  424: 	if (!node->n_from)
  425: 		node->n_items[i].i_flags |= ITEM_FLAG_LOCAL;
  426: 
  427: 	{
  428: 		struct it_item *tab = lookup_tab(&node->n_items[i]);
  429: 
  430: 		if (tab && tab->ii_desc)
  431: 			node->n_items[i].i_desc = tab->ii_desc;
  432: 	}
  433: 
  434: 	if (parent)
  435: 		parent->i_flags |= ITEM_FLAG_HAS_CHILDS;
  436: 
  437: 	return &node->n_items[i];
  438: }
  439: 
  440: void foreach_child(node_t *node, item_t *parent, void (*cb)(item_t *, void *),
  441: 		   void *arg)
  442: {
  443: 	int i;
  444: 
  445: 	for (i = 0; i < node->n_nitems; i++)
  446: 		if (node->n_items[i].i_parent == parent->i_index &&
  447: 		    node->n_items[i].i_flags & ITEM_FLAG_IS_CHILD)
  448: 			cb(&node->n_items[i], arg);
  449: }
  450: 
  451: void reset_item(item_t *i)
  452: {
  453: 	i->i_flags &= ~ITEM_FLAG_UPDATED;
  454: }
  455: 
  456: void remove_unused_items(item_t *i)
  457: {
  458: 	if (--(i->i_lifetime) <= 0) {
  459: 		int m;
  460: 		for (m = 0; m < ATTR_HASH_MAX; m++) {
  461: 			stat_attr_t *a, *next;
  462: 			for (a = i->i_attrs[m]; a; a = next) {
  463: 				next = a->a_next;
  464: 				free(a);
  465: 			}
  466: 		}
  467: 		if (!(i->i_flags & ITEM_FLAG_LOCAL)) {
  468: 			if (i->i_desc)
  469: 				free(i->i_desc);
  470: 		}
  471: 		memset(i, 0, sizeof(item_t));
  472: 	}
  473: }
  474: 
  475: static void calc_rate(rate_t *rate, timestamp_t *ts, int ignore_overflows)
  476: {
  477: 	float diff;
  478: 
  479: 	if (!rate->r_prev_total) {
  480: 		rate->r_prev_total = rate->r_total;
  481: 		COPY_TS(&rate->r_last_update, ts);
  482: 		return;
  483: 	}
  484: 	
  485: 	diff = time_diff(&rate->r_last_update, ts);
  486: 	
  487: 	if (diff >= get_rate_interval()) {
  488: 		if (rate->r_total) {
  489: 			rate_cnt_t old_rate;
  490: 
  491: 			b_cnt_t t = (rate->r_total - rate->r_prev_total);
  492: 			old_rate = rate->r_tps;
  493: 
  494: #ifndef DISABLE_OVERFLOW_WORKAROUND
  495: 			/* HACK:
  496: 			 *
  497: 			 * Workaround for counter overflow, all input methods
  498: 			 * except kstat in 64bit mode use a 32bit counter which
  499: 			 * tends to overflow. We can work around the problem
  500: 			 * when assuming that there will be no  scenario with
  501: 			 * 4GiB/s and no more than 1 overflow per second.
  502: 			 */
  503: 			if (t >= OVERFLOW_LIMIT &&
  504: 			    !rate->r_is64bit &&
  505: 			    !ignore_overflows) {
  506: 				rate->r_tps = OVERFLOW_LIMIT -
  507: 					(rate->r_prev_total - rate->r_total);
  508: 				rate->r_overflows++;
  509: 			} else
  510: #endif
  511: 				rate->r_tps  = (rate_cnt_t) t;
  512: 
  513: 			rate->r_tps /= diff;
  514: 			rate->r_tps = ((rate->r_tps * 3) + old_rate) / 4;
  515: 			rate->r_prev_total = rate->r_total;
  516: 		}
  517: 
  518: 		COPY_TS(&rate->r_last_update, ts);
  519: 	}
  520: }
  521: 
  522: static inline b_cnt_t get_real_total(rate_t *r, unsigned int prev_overflows,
  523: 				     b_cnt_t prev_total)
  524: {
  525: 	b_cnt_t res;
  526: 	unsigned int new_overflows = (r->r_overflows - prev_overflows);
  527: 
  528: #ifndef DISABLE_OVERFLOW_WORKAROUND
  529: 	if (new_overflows)
  530: 		res = (new_overflows * OVERFLOW_LIMIT) + r->r_total - prev_total;
  531: 	else
  532: #endif
  533: 		res = r->r_total - prev_total;
  534: 
  535: 	return res;
  536: }
  537: 
  538: static inline void update_history_data(hist_data_t *hd, rate_t *r,
  539: 				       int index, double diff)
  540: {
  541: 	double t;
  542: 	
  543: 	t = (double) get_real_total(r, hd->hd_overflows,
  544: 	    hd->hd_prev_total) / diff;
  545: 	hd->hd_data[index] = (rate_cnt_t) t;
  546: 	hd->hd_prev_total = r->r_total;
  547: 	hd->hd_overflows = r->r_overflows;
  548: }
  549: 
  550: static void update_history_element(hist_elem_t *he, rate_t *rx, rate_t *tx,
  551: 				   timestamp_t *ts, float unit)
  552: {
  553: 	double diff = time_diff(&he->he_last_update, ts);
  554: 	
  555: 	if (!he->he_last_update.tv_sec)
  556: 		diff = 0.0f;
  557: 
  558: 	/* Do not updated histor for graphs with intervals
  559: 	 * less than the reading interval. */
  560: 	if (get_read_interval() > unit)
  561: 		goto discard;
  562: 
  563: 	/* Discard outdated updates */
  564: 	if (diff >= (unit + (get_hb_factor() * unit)))
  565: 		goto discard;
  566: 
  567: 	if (!he->he_last_update.tv_sec) {
  568: 		he->he_rx.hd_prev_total = rx->r_total;
  569: 		he->he_tx.hd_prev_total = tx->r_total;
  570: 	} else if (get_read_interval() == unit) {
  571: 		update_history_data(&he->he_rx, rx, he->he_index, 1.0f);
  572: 		update_history_data(&he->he_tx, tx, he->he_index, 1.0f);
  573: 	/* The timing code might do shorter intervals than requested to
  574: 	 * adjust previous intervals being too long */
  575: 	} else if (diff >= ((1.0f - get_hb_factor()) * unit)) {
  576: 		update_history_data(&he->he_rx, rx, he->he_index, diff);
  577: 		update_history_data(&he->he_tx, tx, he->he_index, diff);
  578: 	} else {
  579: 		/* Silently discard and give it a chance to come back
  580: 		 * in time. */
  581: 		return;
  582: 	}
  583: 
  584: 	if (he->he_index >= (HISTORY_SIZE - 1))
  585: 		he->he_index = 0;
  586: 	else
  587: 		he->he_index++;
  588: 
  589: 	COPY_TS(&he->he_last_update, ts);
  590: 
  591: 	return;
  592: discard:
  593: 	while(diff > 0.0f) {
  594: 		he->he_rx.hd_data[he->he_index] = UNK_DATA;
  595: 		he->he_tx.hd_data[he->he_index] = UNK_DATA;
  596: 
  597: 		if (he->he_index >= (HISTORY_SIZE - 1))
  598: 			he->he_index = 0;
  599: 		else
  600: 			he->he_index++;
  601: 
  602: 		diff -= unit;
  603: 	}
  604: 
  605: 	he->he_rx.hd_prev_total = rx->r_total;
  606: 	he->he_tx.hd_prev_total = tx->r_total;
  607: 
  608: 	he->he_rx.hd_overflows = rx->r_overflows;
  609: 	he->he_tx.hd_overflows = tx->r_overflows;
  610: 	COPY_TS(&he->he_last_update, ts);
  611: 
  612: }
  613: 
  614: static inline void update_history(history_t *hist, rate_t *rx, rate_t *tx,
  615: 				  timestamp_t *ts)
  616: {
  617: 	if (get_read_interval() != 1.0f)
  618: 		update_history_element(&hist->h_read, rx, tx, ts,
  619: 		    get_read_interval());
  620: 	update_history_element(&hist->h_sec, rx, tx, ts, SECOND);
  621: 	update_history_element(&hist->h_min, rx, tx, ts, MINUTE);
  622: 	update_history_element(&hist->h_hour, rx, tx, ts, HOUR);
  623: 	update_history_element(&hist->h_day, rx, tx, ts, DAY);
  624: }
  625: 
  626: static void update_attr_hist(stat_attr_t *a, void *arg)
  627: {
  628: 	timestamp_t *ts = (timestamp_t *) arg;
  629: 	int ign_of = a->a_flags & ATTR_FLAG_IGNORE_OVERFLOWS;
  630: 
  631: 	if (ts == NULL)
  632: 		ts = &rtiming.rt_last_read;
  633: 
  634: 	if (a->a_flags & ATTR_FLAG_IS_RATE) {
  635: 		a->a_rx.r_tps = a->a_rx.r_total;
  636: 		a->a_tx.r_tps = a->a_tx.r_total;
  637: 	} else {
  638: 		calc_rate(&a->a_rx, ts, ign_of);
  639: 		calc_rate(&a->a_tx, ts, ign_of);
  640: 	}
  641: 
  642: 	if (a->a_flags & ATTR_FLAG_HISTORY) {
  643: 		stat_attr_hist_t *ah = (stat_attr_hist_t *) a;
  644: 		update_history(&ah->a_hist, &ah->a_rx, &ah->a_tx, ts);
  645: 	}
  646: }
  647: 
  648: void notify_update(item_t *i, timestamp_t *ts)
  649: {
  650: 	struct it_item *tab;
  651: 	stat_attr_t *a;
  652: 
  653: 	i->i_flags |= ITEM_FLAG_UPDATED;
  654: 	foreach_attr(i, &update_attr_hist, ts);
  655: 	
  656: 	a = lookup_attr(i, i->i_major_attr);
  657: 	tab = lookup_tab(i);
  658: 
  659: 	if (tab && a) {
  660: 		rate_cnt_t rx = attr_get_rx_rate(a);
  661: 		rate_cnt_t tx = attr_get_tx_rate(a);
  662: 
  663: 		if (tab->ii_rx_max) {
  664: 			if (rx)
  665: 				i->i_rx_usage = (100.0f / (tab->ii_rx_max / rx));
  666: 			else
  667: 				i->i_rx_usage = 0;
  668: 		} else
  669: 			i->i_rx_usage = -1;
  670: 
  671: 		if (tab->ii_tx_max) {
  672: 			if (tx)
  673: 				i->i_tx_usage = (100.0f / (tab->ii_tx_max / tx));
  674: 			else
  675: 				i->i_tx_usage = 0;
  676: 		} else
  677: 			i->i_tx_usage = -1;
  678: 	} else if (!i->i_node || !i->i_node->n_from) {
  679: 		i->i_rx_usage = -1;
  680: 		i->i_tx_usage = -1;
  681: 	}
  682: }
  683: 
  684: void increase_lifetime(item_t *i, int l)
  685: {
  686: 	i->i_lifetime = l*get_lifetime();
  687: }
  688: 
  689: void update_attr(item_t *i, int type, b_cnt_t rx, b_cnt_t tx, int flags)
  690: {
  691: 	stat_attr_t *a;
  692: 	uint8_t h = attr_hash(type);
  693: 	
  694: 	for (a = i->i_attrs[h]; a; a = a->a_next)
  695: 		if (a->a_type == type)
  696: 			goto found;
  697: 	
  698: 	if (collect_history(type)) {
  699: 		a = xcalloc(1, sizeof(stat_attr_hist_t));
  700: 		a->a_flags |= ATTR_FLAG_HISTORY;
  701: 	} else
  702: 		a = xcalloc(1, sizeof(stat_attr_t));
  703: 
  704: 	a->a_type = type;
  705: 	a->a_unit = attr_unit(a->a_type);
  706: 	if (attr_ignore_overflows(a->a_type))
  707: 		a->a_flags |= ATTR_FLAG_IGNORE_OVERFLOWS;
  708: 	if (attr_is_rate(a->a_type))
  709: 		a->a_flags |= ATTR_FLAG_IS_RATE;
  710: 
  711: 	a->a_next = i->i_attrs[h];
  712: 	i->i_attrs[h] = a;
  713: 	i->i_nattrs++;
  714: 
  715: found:
  716: 	if (flags & IS64BIT)
  717: 		a->a_rx.r_is64bit = a->a_tx.r_is64bit = 1;
  718: 
  719: 	if (flags & RX_PROVIDED) {
  720: 		a->a_rx.r_total = rx;
  721: 		a->a_flags |= ATTR_FLAG_RX_ENABLED;
  722: 		update_ts(&a->a_updated); /* XXX: use read ts */
  723: 	}
  724: 
  725: 	if (flags & TX_PROVIDED) {
  726: 		a->a_tx.r_total = tx;
  727: 		a->a_flags |= ATTR_FLAG_TX_ENABLED;
  728: 		update_ts(&a->a_updated);
  729: 	}
  730: }
  731: 
  732: 
  733: item_t * get_item(node_t *node, int index)
  734: {
  735: 	int i;
  736: 
  737: 	for (i = 0; i < node->n_nitems; i++)
  738: 		if (node->n_items[i].i_index == index)
  739: 			return &node->n_items[i];
  740: 	return NULL;
  741: }
  742: 
  743: stat_attr_t *current_attr(int graph)
  744: {
  745: 	int i, c;
  746: 	item_t *it = get_current_item();
  747: 	stat_attr_t *a;
  748: 
  749: 	if (it == NULL)
  750: 		return NULL;
  751: 
  752: 	for (i = 0, c = 0; i < ATTR_HASH_MAX; i++)
  753: 		for (a = it->i_attrs[i]; a; a = a->a_next, c++)
  754: 			if (c == it->i_attr_sel[graph])
  755: 				return a;
  756: 
  757: 	return NULL;
  758: }
  759: 
  760: int first_attr(void)
  761: {
  762: 	int i, c;
  763: 	stat_attr_t *a;
  764: 	item_t *it = get_current_item();
  765: 	if (it == NULL)
  766: 		return EMPTY_LIST;
  767: 
  768: 	for (i = 0, c = 0; i < ATTR_HASH_MAX; i++) {
  769: 		for (a = it->i_attrs[i]; a; a = a->a_next) {
  770: 			if (a->a_flags & ATTR_FLAG_HISTORY) {
  771: 				it->i_attr_sel[it->i_graph_sel] = c;
  772: 				return 0;
  773: 			} else
  774: 				c++;
  775: 		}
  776: 	}
  777: 
  778: 	return EMPTY_LIST;
  779: }
  780: 
  781: int next_attr(void)
  782: {
  783: 	item_t *it = get_current_item();
  784: 	if (it == NULL)
  785: 		return EMPTY_LIST;
  786: 
  787: 	if (it->i_attr_sel[it->i_graph_sel] >= (it->i_nattrs - 1))
  788: 		return first_attr();
  789: 	else {
  790: 		stat_attr_t *a = current_attr(it->i_graph_sel);
  791: 		int i, n = it->i_attr_sel[it->i_graph_sel] + 1;
  792: 
  793: 		if (a) {
  794: 			stat_attr_t *b = a->a_next;
  795: 			i = attr_hash(a->a_type);
  796: 			if (!b)
  797: 				i++;
  798: 			for (; i < ATTR_HASH_MAX; i++) {
  799: 				for (a = b ? : it->i_attrs[i]; a; a = a->a_next) {
  800: 					if (!(a->a_flags & ATTR_FLAG_HISTORY)) {
  801: 						n++;
  802: 						continue;
  803: 					}
  804: 					b = NULL;
  805: 					it->i_attr_sel[it->i_graph_sel] = n;
  806: 					return 0;
  807: 				}
  808: 			}
  809: 		}
  810: 	
  811: 		return first_attr();
  812: 	}
  813: 
  814: 	return 0;
  815: }
  816: 
  817: 
  818: int set_graph_unit(int unit)
  819: {
  820: 	item_t *it = get_current_item();
  821: 	if (it == NULL)
  822: 		return EMPTY_LIST;
  823: 
  824: 	it->i_unit[it->i_graph_sel] = unit;
  825: 
  826: 	return 0;
  827: }

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