File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / bmon / src / attr.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 14:58:35 2019 UTC (5 years, 8 months ago) by misho
Branches: bmon, MAIN
CVS tags: v4_0p0, HEAD
bmon ver 4.0

    1: /*
    2:  * attr.c		Attributes
    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/attr.h>
   29: #include <bmon/history.h>
   30: #include <bmon/element.h>
   31: #include <bmon/unit.h>
   32: #include <bmon/input.h>
   33: #include <bmon/utils.h>
   34: 
   35: #if 0
   36: 
   37: #define MAX_POLICY             255
   38: 
   39: static char * allowed_attrs[MAX_POLICY];
   40: static char * denied_attrs[MAX_POLICY];
   41: static int allow_all_attrs;
   42: 
   43: #endif
   44: 
   45: static LIST_HEAD(attr_def_list);
   46: static int attr_id_gen = 1;
   47: 
   48: struct attr_def *attr_def_lookup(const char *name)
   49: {
   50: 	struct attr_def *def;
   51: 
   52: 	list_for_each_entry(def, &attr_def_list, ad_list)
   53: 		if (!strcmp(name, def->ad_name))
   54: 			return def;
   55: 
   56: 	return NULL;
   57: }
   58: 
   59: struct attr_def *attr_def_lookup_id(int id)
   60: {
   61: 	struct attr_def *def;
   62: 
   63: 	list_for_each_entry(def, &attr_def_list, ad_list)
   64: 		if (def->ad_id == id)
   65: 			return def;
   66: 
   67: 	return NULL;
   68: }
   69: 
   70: #if 0
   71: int foreach_attr_type(int (*cb)(struct attr_type *, void *), void *arg)
   72: {
   73: 	int i, err = 0;
   74: 
   75: 	for (i = 0; i < NAME_HASHSIZ; i++) {
   76: 		struct attr_type *t;
   77: 		for (t = attr_ht_name[i]; t; t = t->at_next_name) {
   78: 			err = cb(t, arg);
   79: 			if (err < 0)
   80: 				break;
   81: 		}
   82: 	}
   83: 
   84: 	return err;
   85: }
   86: #endif
   87: 
   88: int attr_def_add(const char *name, const char *desc, struct unit *unit,
   89: 		 int type, int flags)
   90: {
   91: 	struct attr_def *def;
   92: 
   93: 	if ((def = attr_def_lookup(name)))
   94: 		return def->ad_id;
   95: 
   96: 	def = xcalloc(1, sizeof(*def));
   97: 
   98: 	def->ad_id = attr_id_gen++;
   99: 	def->ad_name = strdup(name);
  100: 
  101: 	def->ad_description = strdup(desc ? : "");
  102: 	def->ad_type = type;
  103: 	def->ad_unit = unit;
  104: 	def->ad_flags = flags;
  105: 
  106: 	list_add_tail(&def->ad_list, &attr_def_list);
  107: 
  108: 	DBG("New attribute %s desc=\"%s\" unit=%s type=%d",
  109: 	    def->ad_name, def->ad_description, def->ad_unit->u_name, type);
  110: 
  111: 	return def->ad_id;
  112: }
  113: 
  114: static void attr_def_free(struct attr_def *def)
  115: {
  116: 	if (!def)
  117: 		return;
  118: 
  119: 	xfree(def->ad_name);
  120: 	xfree(def->ad_description);
  121: 	xfree(def);
  122: }
  123: 
  124: int attr_map_load(struct attr_map *map, size_t size)
  125: {
  126: 	int i, nfailed = 0;
  127: 
  128: 	for (i = 0; i < size; i++) {
  129: 		struct attr_map *m = &map[i];
  130: 		struct unit *u;
  131: 
  132: 		if (!(u = unit_lookup(m->unit))) {
  133: 			nfailed++;
  134: 			continue;
  135: 		}
  136: 
  137: 		m->attrid = attr_def_add(m->name, m->description, u,
  138: 					 m->type, m->flags);
  139: 	}
  140: 
  141: 	return nfailed;
  142: }
  143: 
  144: static inline unsigned int attr_hash(int id)
  145: {
  146: 	return id % ATTR_HASH_SIZE;
  147: }
  148: 
  149: struct attr *attr_lookup(const struct element *e, int id)
  150: {
  151: 	unsigned int hash = attr_hash(id);
  152: 	struct attr *attr;
  153: 
  154: 	list_for_each_entry(attr, &e->e_attrhash[hash], a_list)
  155: 		if (attr->a_def->ad_id == id)
  156: 			return attr;
  157: 
  158: 	return NULL;
  159: }
  160: 
  161: static int collect_history(struct element *e, struct attr_def *def)
  162: {
  163: 	int n;
  164: 
  165: 	if (def->ad_flags & ATTR_FORCE_HISTORY)
  166: 		return 1;
  167: 
  168: 	for (n = 0; n <= GT_MAX; n++)
  169: 		if (e->e_key_attr[n] == def)
  170: 			return 1;
  171: 
  172: 	return 0;
  173: #if 0
  174: 	if (!allowed_attrs[0] && !denied_attrs[0]) {
  175: 		if (!strcmp(ad->ad_name, "bytes") ||
  176: 		    !strcmp(ad->ad_name, "packets"))
  177: 			return 1;
  178: 		else
  179: 			return 0;
  180: 	}
  181: 
  182: 	if (!allowed_attrs[0]) {
  183: 		for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
  184: 			if (!strcasecmp(denied_attrs[n], ad->ad_name))
  185: 				return 0;
  186: 		return 1;
  187: 	}
  188: 
  189: 	for (n = 0; n < MAX_POLICY && denied_attrs[n]; n++)
  190: 		if (!strcasecmp(denied_attrs[n], ad->ad_name))
  191: 			return 0;
  192: 	
  193: 	for (n=0; n < MAX_POLICY && allowed_attrs[n]; n++)
  194: 		if (!strcasecmp(allowed_attrs[n], ad->ad_name))
  195: 			return 1;
  196: #endif
  197: }
  198: 
  199: #if 0
  200: 
  201: void attr_parse_policy(const char *policy)
  202: {
  203: 	static int set = 0;
  204: 	int i, a = 0, d = 0, f = 0;
  205: 	char *p, *s;
  206: 
  207: 	if (set)
  208: 		return;
  209: 	set = 1;
  210: 
  211: 	if (!strcasecmp(policy, "all")) {
  212: 		allow_all_attrs = 1;
  213: 		return ;
  214: 	}
  215: 
  216: 	s = strdup(policy);
  217: 	
  218: 	for (i = 0, p = s; ; i++) {
  219: 		if (s[i] == ',' || s[i] == '\0') {
  220: 
  221: 			f = s[i] == '\0' ? 1 : 0;
  222: 			s[i] = '\0';
  223: 			
  224: 			if ('!' == *p) {
  225: 				if (d > (MAX_POLICY - 1))
  226: 					break;
  227: 				denied_attrs[d++] = strdup(++p);
  228: 			} else {
  229: 				if(a > (MAX_POLICY - 1))
  230: 					break;
  231: 				allowed_attrs[a++] = strdup(p);
  232: 			}
  233: 			
  234: 			if (f)
  235: 				break;
  236: 			
  237: 			p = &s[i+1];
  238: 		}
  239: 	}
  240: 	
  241: 	xfree(s);
  242: }
  243: 
  244: #endif
  245: 
  246: void attr_start_collecting_history(struct attr *attr)
  247: {
  248: 	if (attr->a_flags & ATTR_DOING_HISTORY)
  249: 		return;
  250: 
  251: 	DBG("Starting to collect history for attribute %s",
  252: 	    attr->a_def->ad_name);
  253: 
  254: 	history_attach(attr);
  255: 	attr->a_flags |= ATTR_DOING_HISTORY;
  256: }
  257: 
  258: static int attrcmp(struct element *e, struct attr *a, struct attr *b)
  259: {
  260: 	/* major key attribute is always first */
  261: 	if (e->e_key_attr[GT_MAJOR] == b->a_def)
  262: 		return 1;
  263: 
  264: 	/* minor key attribte is always second */
  265: 	if (e->e_key_attr[GT_MINOR] == b->a_def)
  266: 		return (e->e_key_attr[GT_MAJOR] == a->a_def) ? -1 : 1;
  267: 
  268: 	/* otherwise sort by alphabet */
  269: 	return strcasecmp(a->a_def->ad_description, b->a_def->ad_description);
  270: }
  271: 
  272: void attr_update(struct element *e, int id, uint64_t rx, uint64_t tx, int flags)
  273: {
  274: 	struct attr *attr, *n;
  275: 	int update_ts = 0;
  276: 
  277: 	if (!(attr = attr_lookup(e, id))) {
  278: 		unsigned int hash = attr_hash(id);
  279: 		struct attr_def *def;
  280: 
  281: 		if (!(def = attr_def_lookup_id(id)))
  282: 			return;
  283: 
  284: 		DBG("Tracking new attribute %d (\"%s\") of element %s",
  285: 		    def->ad_id, def->ad_name, e->e_name);
  286: 
  287: 		attr = xcalloc(1, sizeof(*attr));
  288: 		attr->a_def = def;
  289: 		attr->a_flags = def->ad_flags;
  290: 
  291: 		init_list_head(&attr->a_history_list);
  292: 
  293: 		if (collect_history(e, def))
  294: 			attr_start_collecting_history(attr);
  295: 
  296: 		list_add_tail(&attr->a_list, &e->e_attrhash[hash]);
  297: 		e->e_nattrs++;
  298: 
  299: 		list_for_each_entry(n, &e->e_attr_sorted, a_sort_list) {
  300: 			if (attrcmp(e, attr, n) < 0) {
  301: 				list_add_tail(&attr->a_sort_list,
  302: 					      &n->a_sort_list);
  303: 				goto inserted;
  304: 			}
  305: 		}
  306: 
  307: 		list_add_tail(&attr->a_sort_list, &e->e_attr_sorted);
  308: 	}
  309: 
  310: inserted:
  311: 	if (flags & UPDATE_FLAG_RX) {
  312: 		attr->a_rx_rate.r_current = rx;
  313: 		attr->a_flags |= ATTR_RX_ENABLED;
  314: 		update_ts = 1;
  315: 	}
  316: 
  317: 	if (flags & UPDATE_FLAG_TX) {
  318: 		attr->a_tx_rate.r_current = tx;
  319: 		attr->a_flags |= ATTR_TX_ENABLED;
  320: 		update_ts = 1;
  321: 	}
  322: 
  323: 	if (update_ts)
  324: 		update_timestamp(&attr->a_last_update);
  325: 
  326: 	DBG("Updated attribute %d (\"%s\") of element %s", id, attr->a_def->ad_name, e->e_name);
  327: }
  328: 
  329: void attr_free(struct attr *a)
  330: {
  331: 	struct history *h, *n;
  332: 
  333: 	list_for_each_entry_safe(h, n, &a->a_history_list, h_list)
  334: 		history_free(h);
  335: 
  336: 	list_del(&a->a_list);
  337: 
  338: 	xfree(a);
  339: }
  340: 
  341: void attr_rate2float(struct attr *a, double *rx, char **rxu, int *rxprec,
  342: 				     double *tx, char **txu, int *txprec)
  343: {
  344: 	struct unit *u = a->a_def->ad_unit;
  345: 
  346: 	*rx = unit_value2str(a->a_rx_rate.r_rate, u, rxu, rxprec);
  347: 	*tx = unit_value2str(a->a_tx_rate.r_rate, u, txu, txprec);
  348: }
  349: 
  350: struct attr *attr_select_first(void)
  351: {
  352: 	struct element *e;
  353: 
  354: 	if (!(e = element_current()))
  355: 		return NULL;
  356: 
  357: 	if (list_empty(&e->e_attr_sorted))
  358: 		e->e_current_attr = NULL;
  359: 	else
  360: 		e->e_current_attr = list_first_entry(&e->e_attr_sorted,
  361: 					struct attr, a_sort_list);
  362: 
  363: 	return e->e_current_attr;
  364: }
  365: 
  366: struct attr *attr_select_last(void)
  367: {
  368: 	struct element *e;
  369: 
  370: 	if (!(e = element_current()))
  371: 		return NULL;
  372: 
  373: 	if (list_empty(&e->e_attr_sorted))
  374: 		e->e_current_attr = NULL;
  375: 	else
  376: 		e->e_current_attr = list_entry(&e->e_attr_sorted,
  377: 					   struct attr, a_sort_list);
  378: 
  379: 	return e->e_current_attr;
  380: }
  381: 
  382: struct attr *attr_select_next(void)
  383: {
  384: 	struct element *e;
  385: 	struct attr *a;
  386: 
  387: 	if (!(e = element_current()))
  388: 		return NULL;
  389: 
  390: 	if (!(a = e->e_current_attr))
  391: 		return attr_select_first();
  392: 
  393: 	if (a->a_sort_list.next != &e->e_attr_sorted)
  394: 		e->e_current_attr = list_entry(a->a_sort_list.next,
  395: 					   struct attr, a_sort_list);
  396: 	else
  397: 		return attr_select_first();
  398: 
  399: 	return e->e_current_attr;
  400: }
  401: 
  402: struct attr *attr_select_prev(void)
  403: {
  404: 	struct element *e;
  405: 	struct attr *a;
  406: 
  407: 	if (!(e = element_current()))
  408: 		return NULL;
  409: 
  410: 	if (!(a = e->e_current_attr))
  411: 		return attr_select_last();
  412: 
  413: 	if (a->a_sort_list.prev != &e->e_attr_sorted)
  414: 		e->e_current_attr = list_entry(a->a_sort_list.prev,
  415: 					   struct attr, a_sort_list);
  416: 	else
  417: 		return attr_select_last();
  418: 
  419: 	return e->e_current_attr;
  420: 
  421: }
  422: 
  423: struct attr *attr_current(void)
  424: {
  425: 	struct element *e;
  426: 
  427: 	if (!(e = element_current()))
  428: 		return NULL;
  429: 
  430: 	if (!e->e_current_attr)
  431: 		return attr_select_first();
  432: 
  433: 	return e->e_current_attr;
  434: }
  435: 
  436: #if 0
  437: int __first_attr(struct item *item, int graph)
  438: {
  439: 	int i;
  440: 	struct attr *a;
  441: 
  442: 	for (i = 0; i < ATTR_HASH_MAX; i++) {
  443: 		for (a = item->i_attrs[i]; a; a = a->a_next) {
  444: 			if (a->a_flags & ATTR_FLAG_HISTORY) {
  445: 				item->i_attr_sel[graph] = a;
  446: 				return 0;
  447: 			}
  448: 		}
  449: 	}
  450: 
  451: 	return EMPTY_LIST;
  452: }
  453: 
  454: int __next_attr(struct item *item, int graph)
  455: {
  456: 	int hash;
  457: 	struct attr *attr, *next;
  458: 
  459: 	if (item->i_attr_sel[graph] == NULL)
  460: 		return __first_attr(item, graph);
  461: 
  462: 	attr = item->i_attr_sel[graph];
  463: 	hash = attr_hash(attr->a_def->ad_id);
  464: 	next = attr->a_next;
  465: 
  466: 	if (next == NULL)
  467: 		hash++;
  468: 
  469: 	for (; hash < ATTR_HASH_MAX; hash++) {
  470: 		if (next) {
  471: 			attr = next;
  472: 			next = NULL;
  473: 		} else
  474: 			attr = item->i_attrs[hash];
  475: 
  476: 		for (; attr; attr = attr->a_next) {
  477: 			if (!(attr->a_flags & ATTR_FLAG_HISTORY))
  478: 				continue;
  479: 			item->i_attr_sel[graph] = attr;
  480: 			return 0;
  481: 		}
  482: 	}
  483: 
  484: 	return __first_attr(item, graph);
  485: }
  486: 
  487: struct attr *attr_current(struct item *item, int graph)
  488: {
  489: 	if (item->i_attr_sel[graph] == NULL)
  490: 		__first_attr(item, graph);
  491: 
  492: 	return item->i_attr_sel[graph];
  493: }
  494: 
  495: int attr_first(void)
  496: {
  497: 	struct item *item = item_current();
  498: 	
  499: 	if (item == NULL)
  500: 		return EMPTY_LIST;
  501: 
  502: 	return __first_attr(item, item->i_graph_sel);
  503: }
  504: 
  505: int attr_next(void)
  506: {
  507: 	struct item *item = item_current();
  508: 	
  509: 	if (item == NULL)
  510: 		return EMPTY_LIST;
  511: 
  512: 	return __next_attr(item, item->i_graph_sel);
  513: }
  514: #endif
  515: 
  516: static float __calc_usage(double rate, uint64_t max)
  517: {
  518: 	if (!max)
  519: 		return FLT_MAX;
  520: 
  521: 	if (!rate)
  522: 		return 0.0f;
  523: 
  524: 	return 100.0f / ((double) max / (rate * cfg_rate_interval));
  525: }
  526: 
  527: uint64_t rate_get_total(struct rate *r)
  528: {
  529: 	return r->r_total - r->r_reset;
  530: }
  531: 
  532: void attr_calc_usage(struct attr *a, float *rx, float *tx,
  533: 		     uint64_t rxmax, uint64_t txmax)
  534: {
  535: 	if (a->a_def->ad_type == ATTR_TYPE_PERCENT) {
  536: 		*rx = a->a_rx_rate.r_total;
  537: 		*tx = a->a_tx_rate.r_total;
  538: 	} else {
  539: 		*rx = __calc_usage(a->a_rx_rate.r_rate, rxmax);
  540: 		*tx = __calc_usage(a->a_tx_rate.r_rate, txmax);
  541: 	}
  542: }
  543: 
  544: static void calc_counter_rate(struct attr *a, struct rate *rate,
  545: 			      timestamp_t *ts)
  546: {
  547: 	uint64_t delta, prev_total;
  548: 	float diff, old_rate;
  549: 
  550: 	if (rate->r_current < rate->r_prev) {
  551: 		/* Overflow detected */
  552: 		if (a->a_flags & ATTR_IGNORE_OVERFLOWS)
  553: 			delta = rate->r_current;
  554: 		else {
  555: 			if (a->a_flags & ATTR_TRUE_64BIT)
  556: 				delta = 0xFFFFFFFFFFFFFFFFULL - rate->r_prev;
  557: 			else
  558: 				delta = 0xFFFFFFFFULL - rate->r_prev;
  559: 
  560: 			delta += rate->r_current + 1;
  561: 		}
  562: 	} else
  563: 		delta = rate->r_current - rate->r_prev;
  564: 
  565: 	prev_total = rate->r_total;
  566: 	rate->r_total += delta;
  567: 	rate->r_prev = rate->r_current;
  568: 
  569: 	if (!prev_total) {
  570: 		/*
  571: 		 * No previous records exists, reset time to now to
  572: 		 * avoid doing unnecessary calculation, this behaviour
  573: 		 * continues as long as the counter stays 0.
  574: 		 */
  575: 		goto out;
  576: 	}
  577: 	
  578: 	diff = timestamp_diff(&rate->r_last_calc, ts);
  579: 	if (diff < (cfg_rate_interval - cfg_rate_variance))
  580: 		return;
  581: 
  582: 	old_rate = rate->r_rate;
  583: 
  584: 	if (rate->r_total < prev_total) {
  585: 		/* overflow */
  586: 		delta = 0xFFFFFFFFFFFFFFFFULL - prev_total;
  587: 		delta += rate->r_total + 1;
  588: 	} else
  589: 		delta = rate->r_total - prev_total;
  590: 
  591: 	rate->r_rate = delta / diff;
  592: 
  593: 	if (old_rate)
  594: 		rate->r_rate = ((rate->r_rate * 3.0f) + old_rate) / 4.0f;
  595: 
  596: out:
  597: 	copy_timestamp(&rate->r_last_calc, ts);
  598: }
  599: 
  600: static void calc_rate_total(struct attr *a, struct rate *rate, timestamp_t *ts)
  601: {
  602: 	rate->r_prev = rate->r_rate = rate->r_total = rate->r_current;
  603: 	copy_timestamp(&rate->r_last_calc, ts);
  604: }
  605: 
  606: void attr_notify_update(struct attr *a, timestamp_t *ts)
  607: {
  608: 	switch (a->a_def->ad_type) {
  609: 	case ATTR_TYPE_RATE:
  610: 	case ATTR_TYPE_PERCENT:
  611: 		calc_rate_total(a, &a->a_rx_rate, ts);
  612: 		calc_rate_total(a, &a->a_tx_rate, ts);
  613: 		break;
  614: 
  615: 	case ATTR_TYPE_COUNTER:
  616: 		calc_counter_rate(a, &a->a_rx_rate, ts);
  617: 		calc_counter_rate(a, &a->a_tx_rate, ts);
  618: 		break;
  619: 	default:
  620: 		DBG("Attribute update of unknown type");
  621: 		break;
  622: 	}
  623: 
  624: 	if (a->a_flags & ATTR_DOING_HISTORY) {
  625: 		struct history *h;
  626: 
  627: 		DBG("Updating history of attribute %d (\"%s\")", a->a_def->ad_id, a->a_def->ad_name);
  628: 
  629: 		list_for_each_entry(h, &a->a_history_list, h_list)
  630: 			history_update(a, h, ts);
  631: 	}
  632: }
  633: 
  634: void attr_reset_counter(struct attr *a)
  635: {
  636: 	if (a->a_def->ad_type == ATTR_TYPE_COUNTER) {
  637: 		a->a_rx_rate.r_reset = a->a_rx_rate.r_total;
  638: 		a->a_tx_rate.r_reset = a->a_tx_rate.r_total;
  639: 	}
  640: }
  641: 
  642: static void __exit attr_exit(void)
  643: {
  644: 	struct attr_def *ad, *n;
  645: 
  646: 	list_for_each_entry_safe(ad, n, &attr_def_list, ad_list)
  647: 		attr_def_free(ad);
  648: }

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