summaryrefslogtreecommitdiffstats
path: root/src/graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/graph.c')
-rw-r--r--src/graph.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/graph.c b/src/graph.c
new file mode 100644
index 0000000..3580238
--- /dev/null
+++ b/src/graph.c
@@ -0,0 +1,235 @@
+/*
+ * graph.c Graph creation utility
+ *
+ * Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <bmon/bmon.h>
+#include <bmon/graph.h>
+#include <bmon/input.h>
+#include <bmon/conf.h>
+#include <bmon/history.h>
+#include <bmon/conf.h>
+#include <bmon/unit.h>
+#include <bmon/utils.h>
+
+size_t graph_row_size(struct graph_cfg *cfg)
+{
+ /* +1 for trailing \0 */
+ return cfg->gc_width + 1;
+}
+
+static inline size_t table_size(struct graph_cfg *cfg)
+{
+ return cfg->gc_height * graph_row_size(cfg);
+}
+
+static inline char *at_row(struct graph_cfg *cfg, char *col, int nrow)
+{
+ return col + (nrow * graph_row_size(cfg));
+}
+
+static inline char *at_col(char *row, int ncol)
+{
+ return row + ncol;
+}
+
+static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol)
+{
+ return at_col(at_row(cfg, tbl, nrow), ncol);
+}
+
+static void write_column(struct graph_cfg *cfg, struct graph_table *tbl, int ncol,
+ uint64_t value, double *scale, double half_step)
+{
+ char *col = at_col(tbl->gt_table, ncol);
+ int i;
+
+#if 0
+ if (value == UNK_DATA) {
+ for (i = 0; i < height; i++)
+ *(at_row(g, col, i)) = unk_char;
+#endif
+ if (value) {
+ *(at_row(cfg, col, 0)) = ':';
+
+ for (i = 0; i < cfg->gc_height; i++)
+ if (value >= (scale[i] - half_step))
+ *(at_row(cfg, col, i)) = cfg->gc_foreground;
+ }
+}
+
+static void fill_table(struct graph *g, struct graph_table *tbl,
+ struct history *h, struct history_store *data)
+{
+ struct graph_cfg *cfg = &g->g_cfg;
+ uint64_t max = 0, v;
+ int i, n, t;
+ float half_step, step;
+
+ if (!tbl->gt_table) {
+ tbl->gt_table = xcalloc(table_size(cfg), sizeof(char));
+ tbl->gt_scale = xcalloc(cfg->gc_height, sizeof(double));
+ }
+
+ memset(tbl->gt_table, cfg->gc_background, table_size(cfg));
+
+ /* end each line with a \0 */
+ for (i = 0; i < cfg->gc_height; i++)
+ *tbl_pos(cfg, tbl->gt_table, i, cfg->gc_width) = '\0';
+
+ /* leave table blank if there is no data */
+ if (!h || !data->hs_data)
+ return;
+
+ if (cfg->gc_width > h->h_definition->hd_size)
+ BUG();
+
+ /* find the largest peak */
+ for (n = h->h_index, i = 0; i < cfg->gc_width; i++) {
+ if (--n < 0)
+ n = h->h_definition->hd_size - 1;
+ v = history_data(h, data, n);
+ if (v != HISTORY_UNKNOWN && max < v)
+ max = v;
+ }
+
+ step = (double) max / (double) cfg->gc_height;
+ half_step = step / 2.0f;
+
+ for (i = 0; i < cfg->gc_height; i++)
+ tbl->gt_scale[i] = (double) (i + 1) * step;
+
+ for (n = h->h_index, i = 0; i < cfg->gc_width; i++) {
+ char * col = at_col(tbl->gt_table, i);
+
+ if (--n < 0)
+ n = h->h_definition->hd_size - 1;
+ v = history_data(h, data, n);
+
+ if (v == HISTORY_UNKNOWN) {
+ for (t = 0; t < cfg->gc_height; t++)
+ *(at_row(cfg, col, t)) = cfg->gc_unknown;
+ } else if (v > 0) {
+ *(at_row(cfg, col, 0)) = cfg->gc_noise;
+
+ for (t = 0; t < cfg->gc_height; t++)
+ if (v >= (tbl->gt_scale[t] - half_step))
+ *(at_row(cfg, col, t)) = cfg->gc_foreground;
+ }
+ }
+
+ n = (cfg->gc_height / 3) * 2;
+ if (n >= cfg->gc_height)
+ n = (cfg->gc_height - 1);
+
+ v = unit_divisor(tbl->gt_scale[n], cfg->gc_unit,
+ &tbl->gt_y_unit, NULL);
+
+ for (i = 0; i < cfg->gc_height; i++)
+ tbl->gt_scale[i] /= (double) v;
+}
+
+struct graph *graph_alloc(struct history *h, struct graph_cfg *cfg)
+{
+ struct graph *g;
+
+ if (!cfg->gc_height)
+ BUG();
+
+ g = xcalloc(1, sizeof(*g));
+
+ memcpy(&g->g_cfg, cfg, sizeof(*cfg));
+
+ if (h != NULL &&
+ (cfg->gc_width > h->h_definition->hd_size || !cfg->gc_width))
+ g->g_cfg.gc_width = h->h_definition->hd_size;
+
+ if (!g->g_cfg.gc_width)
+ BUG();
+
+ return g;
+}
+
+void graph_refill(struct graph *g, struct history *h)
+{
+ fill_table(g, &g->g_rx, h, h ? &h->h_rx : NULL);
+ fill_table(g, &g->g_tx, h, h ? &h->h_tx : NULL);
+}
+
+void graph_free(struct graph *g)
+{
+ if (!g)
+ return;
+
+ xfree(g->g_rx.gt_table);
+ xfree(g->g_rx.gt_scale);
+ xfree(g->g_tx.gt_table);
+ xfree(g->g_tx.gt_scale);
+ xfree(g);
+}
+
+#if 0
+
+void new_graph(void)
+{
+ if (ngraphs >= (MAX_GRAPHS - 1))
+ return;
+ set_ngraphs_hard(ngraphs + 1);
+}
+
+void del_graph(void)
+{
+ if (ngraphs <= 1)
+ return;
+ set_ngraphs_hard(ngraphs - 1);
+}
+
+int next_graph(void)
+{
+ struct item *it = item_current();
+ if (it == NULL)
+ return EMPTY_LIST;
+
+ if (it->i_graph_sel >= (ngraphs - 1))
+ it->i_graph_sel = 0;
+ else
+ it->i_graph_sel++;
+
+ return 0;
+}
+
+int prev_graph(void)
+{
+ struct item *it = item_current();
+ if (it == NULL)
+ return EMPTY_LIST;
+
+ if (it->i_graph_sel <= 0)
+ it->i_graph_sel = ngraphs - 1;
+ else
+ it->i_graph_sel--;
+
+ return 0;
+}
+
+#endif