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