|
version 1.1.1.1, 2012/02/21 22:19:56
|
version 1.1.1.3, 2019/10/21 14:58:35
|
|
Line 1
|
Line 1
|
| /* |
/* |
| * graph.c Graph creation utility |
* graph.c Graph creation utility |
| * |
* |
| * Copyright (c) 2001-2005 Thomas Graf <tgraf@suug.ch> | * 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 |
* Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
* copy of this software and associated documentation files (the "Software"), |
|
Line 26
|
Line 27
|
| #include <bmon/graph.h> |
#include <bmon/graph.h> |
| #include <bmon/input.h> |
#include <bmon/input.h> |
| #include <bmon/conf.h> |
#include <bmon/conf.h> |
| #include <bmon/item.h> | #include <bmon/history.h> |
| #include <bmon/node.h> | |
| #include <bmon/conf.h> |
#include <bmon/conf.h> |
| |
#include <bmon/unit.h> |
| #include <bmon/utils.h> |
#include <bmon/utils.h> |
| |
|
| |
size_t graph_row_size(struct graph_cfg *cfg) |
| |
{ |
| |
/* +1 for trailing \0 */ |
| |
return cfg->gc_width + 1; |
| |
} |
| |
|
| static void put_col(table_t *t, int data_idx, hist_data_t *src, int hist_idx, | static inline size_t table_size(struct graph_cfg *cfg) |
| double half_step) | |
| { |
{ |
| int i; | return cfg->gc_height * graph_row_size(cfg); |
| char *col = D_AT_COL(t->t_data, data_idx); | } |
| |
|
| rate_cnt_t tot = src->hd_data[hist_idx]; | static inline char *at_row(struct graph_cfg *cfg, char *col, int nrow) |
| | { |
| | return col + (nrow * graph_row_size(cfg)); |
| | } |
| |
|
| if (tot == UNK_DATA) { | static inline char *at_col(char *row, int ncol) |
| for (i = 0; i < t->t_height; i++) | { |
| *(D_AT_ROW(col, i)) = get_unk_char(); | return row + ncol; |
| } else if (tot) { | |
| *(D_AT_ROW(col, 0)) = ':'; | |
| | |
| for (i = 0; i < t->t_height; i++) | |
| if (tot >= (t->t_y_scale[i] - half_step)) | |
| *(D_AT_ROW(col, i)) = get_fg_char(); | |
| } | |
| } |
} |
| |
|
| static void create_table(table_t *t, hist_data_t *src, int index, int height, | static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol) |
| int unit) | |
| { |
{ |
| int i, di; | return at_col(at_row(cfg, tbl, nrow), ncol); |
| size_t dsize = height * (HISTORY_SIZE + 1); | } |
| rate_cnt_t max = 0; | |
| double half_step, step; | |
| | |
| t->t_index = index; | |
| t->t_height = height; | |
| t->t_y_scale = xcalloc(height, sizeof(double)); | |
| t->t_data = xcalloc(dsize, sizeof(char)); | |
| |
|
| memset(t->t_data, get_bg_char(), dsize); | 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; |
| | double v; |
| | int i, n, t; |
| | float half_step, step; |
| |
|
| for (i = 0; i < height; i++) | if (!tbl->gt_table) { |
| *(D_AT_COL(D_AT_ROW(t->t_data, i), HISTORY_SIZE)) = '\0'; | tbl->gt_table = xcalloc(table_size(cfg), sizeof(char)); |
| | tbl->gt_scale = xcalloc(cfg->gc_height, sizeof(double)); |
| | } |
| |
|
| for (i = 0; i < HISTORY_SIZE; i++) | memset(tbl->gt_table, cfg->gc_background, table_size(cfg)); |
| if (max < src->hd_data[i] && src->hd_data[i] != UNK_DATA) | |
| max = src->hd_data[i]; | |
| |
|
| step = (double) max / (double) height; | /* end each line with a \0 */ |
| half_step = step / 2.0f; | for (i = 0; i < cfg->gc_height; i++) |
| | *tbl_pos(cfg, tbl->gt_table, i, cfg->gc_width) = '\0'; |
| |
|
| for (i = 0; i < height; i++) | /* leave table blank if there is no data */ |
| t->t_y_scale[i] = (double) (i + 1) * step; | if (!h || !data->hs_data) |
| | return; |
| |
|
| for (di = 0, i = (index - 1); i >= 0; di++, i--) | if (cfg->gc_width > h->h_definition->hd_size) |
| put_col(t, di, src, i, half_step); | BUG(); |
| |
|
| for (i = (HISTORY_SIZE - 1); di < HISTORY_SIZE; di++, i--) | /* find the largest peak */ |
| put_col(t, di, src, i, half_step); | 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; |
| b_cnt_t div; | half_step = step / 2.0f; |
| int h = (height / 3) * 2; | |
| |
|
| if (h >= height) | for (i = 0; i < cfg->gc_height; i++) |
| h = (height - 1); | tbl->gt_scale[i] = (double) (i + 1) * step; |
| |
|
| div = get_divisor(t->t_y_scale[h], unit, &t->t_y_unit, NULL); | for (n = h->h_index, i = 0; i < cfg->gc_width; i++) { |
| | char * col = at_col(tbl->gt_table, i); |
| for (i = 0; i < height; i++) | |
| t->t_y_scale[i] /= (double) div; | |
| } | |
| } | |
| |
|
| graph_t * create_graph(hist_elem_t *src, int height, int unit) | if (--n < 0) |
| { | n = h->h_definition->hd_size - 1; |
| graph_t *g; | v = history_data(h, data, n); |
| |
|
| g = xcalloc(1, sizeof(graph_t)); | 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; |
| |
|
| create_table(&g->g_rx, &src->he_rx, src->he_index, height, unit); | for (t = 0; t < cfg->gc_height; t++) |
| create_table(&g->g_tx, &src->he_tx, src->he_index, height, unit); | if (v >= (tbl->gt_scale[t] - half_step)) |
| | *(at_row(cfg, col, t)) = cfg->gc_foreground; |
| | } |
| | } |
| |
|
| return g; | 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] /= v; |
| } |
} |
| |
|
| graph_t * create_configued_graph(history_t *src, int height, int unit, | struct graph *graph_alloc(struct history *h, struct graph_cfg *cfg) |
| int x_unit) | |
| { |
{ |
| graph_t *g; | struct graph *g; |
| hist_elem_t *e = NULL; | |
| char *u = "s"; | |
| int h = 0; | |
| |
|
| switch (x_unit) { | if (!cfg->gc_height) |
| case X_SEC: u = "s"; e = &src->h_sec; break; | |
| case X_MIN: u = "m"; e = &src->h_min; break; | |
| case X_HOUR: u = "h"; e = &src->h_hour; break; | |
| case X_DAY: u = "d"; e = &src->h_day; break; | |
| case X_READ: { | |
| if (get_read_interval() != 1.0f) { | |
| char buf[32]; | |
| float ri = get_read_interval(); | |
| |
| snprintf(buf, sizeof(buf), "(%.2fs)", ri); | |
| u = strdup(buf); | |
| h = 1; | |
| e = &src->h_read; | |
| } else { | |
| u = "s"; | |
| e = &src->h_sec; | |
| } | |
| } | |
| break; | |
| } | |
| |
| if (NULL == e) | |
| BUG(); |
BUG(); |
| |
|
| g = create_graph(e, height, unit); | g = xcalloc(1, sizeof(*g)); |
| |
|
| if (h) | memcpy(&g->g_cfg, cfg, sizeof(*cfg)); |
| g->g_flags |= GRAPH_HAS_FREEABLE_X_UNIT; | |
| |
|
| g->g_rx.t_x_unit = u; | if (h != NULL && |
| g->g_tx.t_x_unit = u; | (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; |
return g; |
| } |
} |
| |
|
| static void free_table(table_t *t) | void graph_refill(struct graph *g, struct history *h) |
| { |
{ |
| xfree(t->t_y_scale); | fill_table(g, &g->g_rx, h, h ? &h->h_rx : NULL); |
| xfree(t->t_data); | fill_table(g, &g->g_tx, h, h ? &h->h_tx : NULL); |
| } |
} |
| |
|
| void free_graph(graph_t *g) | void graph_free(struct graph *g) |
| { |
{ |
| if (g->g_flags & GRAPH_HAS_FREEABLE_X_UNIT) | if (!g) |
| xfree(g->g_rx.t_x_unit); | return; |
| | |
| free_table(&g->g_rx); | xfree(g->g_rx.gt_table); |
| free_table(&g->g_tx); | xfree(g->g_rx.gt_scale); |
| | xfree(g->g_tx.gt_table); |
| | xfree(g->g_tx.gt_scale); |
| xfree(g); |
xfree(g); |
| } |
} |
| |
|
| |
#if 0 |
| |
|
| void new_graph(void) |
void new_graph(void) |
| { |
{ |
| if (get_ngraphs() >= (MAX_GRAPHS - 1)) | if (ngraphs >= (MAX_GRAPHS - 1)) |
| return; |
return; |
| set_ngraphs(get_ngraphs() + 1); | set_ngraphs_hard(ngraphs + 1); |
| } |
} |
| |
|
| void del_graph(void) |
void del_graph(void) |
| { |
{ |
| if (get_ngraphs() <= 1) | if (ngraphs <= 1) |
| return; |
return; |
| set_ngraphs(get_ngraphs() - 1); | set_ngraphs_hard(ngraphs - 1); |
| } |
} |
| |
|
| int next_graph(void) |
int next_graph(void) |
| { |
{ |
| item_t *it = get_current_item(); | struct item *it = item_current(); |
| if (it == NULL) |
if (it == NULL) |
| return EMPTY_LIST; |
return EMPTY_LIST; |
| |
|
| if (it->i_graph_sel >= (get_ngraphs() - 1)) | if (it->i_graph_sel >= (ngraphs - 1)) |
| it->i_graph_sel = 0; |
it->i_graph_sel = 0; |
| else |
else |
| it->i_graph_sel++; |
it->i_graph_sel++; |
|
Line 202 int next_graph(void)
|
Line 201 int next_graph(void)
|
| |
|
| int prev_graph(void) |
int prev_graph(void) |
| { |
{ |
| item_t *it = get_current_item(); | struct item *it = item_current(); |
| if (it == NULL) |
if (it == NULL) |
| return EMPTY_LIST; |
return EMPTY_LIST; |
| |
|
| if (it->i_graph_sel <= 0) |
if (it->i_graph_sel <= 0) |
| it->i_graph_sel = get_ngraphs() - 1; | it->i_graph_sel = ngraphs - 1; |
| else |
else |
| it->i_graph_sel--; |
it->i_graph_sel--; |
| |
|
| return 0; |
return 0; |
| } |
} |
| |
|
| |
#endif |