1: /*
2: * graph.c Graph creation utility
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/graph.h>
28: #include <bmon/input.h>
29: #include <bmon/conf.h>
30: #include <bmon/history.h>
31: #include <bmon/conf.h>
32: #include <bmon/unit.h>
33: #include <bmon/utils.h>
34:
35: size_t graph_row_size(struct graph_cfg *cfg)
36: {
37: /* +1 for trailing \0 */
38: return cfg->gc_width + 1;
39: }
40:
41: static inline size_t table_size(struct graph_cfg *cfg)
42: {
43: return cfg->gc_height * graph_row_size(cfg);
44: }
45:
46: static inline char *at_row(struct graph_cfg *cfg, char *col, int nrow)
47: {
48: return col + (nrow * graph_row_size(cfg));
49: }
50:
51: static inline char *at_col(char *row, int ncol)
52: {
53: return row + ncol;
54: }
55:
56: static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol)
57: {
58: return at_col(at_row(cfg, tbl, nrow), ncol);
59: }
60:
61: static void fill_table(struct graph *g, struct graph_table *tbl,
62: struct history *h, struct history_store *data)
63: {
64: struct graph_cfg *cfg = &g->g_cfg;
65: uint64_t max = 0;
66: double v;
67: int i, n, t;
68: float half_step, step;
69:
70: if (!tbl->gt_table) {
71: tbl->gt_table = xcalloc(table_size(cfg), sizeof(char));
72: tbl->gt_scale = xcalloc(cfg->gc_height, sizeof(double));
73: }
74:
75: memset(tbl->gt_table, cfg->gc_background, table_size(cfg));
76:
77: /* end each line with a \0 */
78: for (i = 0; i < cfg->gc_height; i++)
79: *tbl_pos(cfg, tbl->gt_table, i, cfg->gc_width) = '\0';
80:
81: /* leave table blank if there is no data */
82: if (!h || !data->hs_data)
83: return;
84:
85: if (cfg->gc_width > h->h_definition->hd_size)
86: BUG();
87:
88: /* find the largest peak */
89: for (n = h->h_index, i = 0; i < cfg->gc_width; i++) {
90: if (--n < 0)
91: n = h->h_definition->hd_size - 1;
92: v = history_data(h, data, n);
93: if (v != HISTORY_UNKNOWN && max < v)
94: max = v;
95: }
96:
97: step = (double) max / (double) cfg->gc_height;
98: half_step = step / 2.0f;
99:
100: for (i = 0; i < cfg->gc_height; i++)
101: tbl->gt_scale[i] = (double) (i + 1) * step;
102:
103: for (n = h->h_index, i = 0; i < cfg->gc_width; i++) {
104: char * col = at_col(tbl->gt_table, i);
105:
106: if (--n < 0)
107: n = h->h_definition->hd_size - 1;
108: v = history_data(h, data, n);
109:
110: if (v == HISTORY_UNKNOWN) {
111: for (t = 0; t < cfg->gc_height; t++)
112: *(at_row(cfg, col, t)) = cfg->gc_unknown;
113: } else if (v > 0) {
114: *(at_row(cfg, col, 0)) = cfg->gc_noise;
115:
116: for (t = 0; t < cfg->gc_height; t++)
117: if (v >= (tbl->gt_scale[t] - half_step))
118: *(at_row(cfg, col, t)) = cfg->gc_foreground;
119: }
120: }
121:
122: n = (cfg->gc_height / 3) * 2;
123: if (n >= cfg->gc_height)
124: n = (cfg->gc_height - 1);
125:
126: v = unit_divisor(tbl->gt_scale[n], cfg->gc_unit,
127: &tbl->gt_y_unit, NULL);
128:
129: for (i = 0; i < cfg->gc_height; i++)
130: tbl->gt_scale[i] /= v;
131: }
132:
133: struct graph *graph_alloc(struct history *h, struct graph_cfg *cfg)
134: {
135: struct graph *g;
136:
137: if (!cfg->gc_height)
138: BUG();
139:
140: g = xcalloc(1, sizeof(*g));
141:
142: memcpy(&g->g_cfg, cfg, sizeof(*cfg));
143:
144: if (h != NULL &&
145: (cfg->gc_width > h->h_definition->hd_size || !cfg->gc_width))
146: g->g_cfg.gc_width = h->h_definition->hd_size;
147:
148: if (!g->g_cfg.gc_width)
149: BUG();
150:
151: return g;
152: }
153:
154: void graph_refill(struct graph *g, struct history *h)
155: {
156: fill_table(g, &g->g_rx, h, h ? &h->h_rx : NULL);
157: fill_table(g, &g->g_tx, h, h ? &h->h_tx : NULL);
158: }
159:
160: void graph_free(struct graph *g)
161: {
162: if (!g)
163: return;
164:
165: xfree(g->g_rx.gt_table);
166: xfree(g->g_rx.gt_scale);
167: xfree(g->g_tx.gt_table);
168: xfree(g->g_tx.gt_scale);
169: xfree(g);
170: }
171:
172: #if 0
173:
174: void new_graph(void)
175: {
176: if (ngraphs >= (MAX_GRAPHS - 1))
177: return;
178: set_ngraphs_hard(ngraphs + 1);
179: }
180:
181: void del_graph(void)
182: {
183: if (ngraphs <= 1)
184: return;
185: set_ngraphs_hard(ngraphs - 1);
186: }
187:
188: int next_graph(void)
189: {
190: struct item *it = item_current();
191: if (it == NULL)
192: return EMPTY_LIST;
193:
194: if (it->i_graph_sel >= (ngraphs - 1))
195: it->i_graph_sel = 0;
196: else
197: it->i_graph_sel++;
198:
199: return 0;
200: }
201:
202: int prev_graph(void)
203: {
204: struct item *it = item_current();
205: if (it == NULL)
206: return EMPTY_LIST;
207:
208: if (it->i_graph_sel <= 0)
209: it->i_graph_sel = ngraphs - 1;
210: else
211: it->i_graph_sel--;
212:
213: return 0;
214: }
215:
216: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>