graph.c revision b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5
1af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron/* 2af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * gfio - gui front end for fio - the flexible io tester 3af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * 4af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * Copyright (C) 2012 Stephen M. Cameron <stephenmcameron@gmail.com> 5af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * 6af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * The license below covers all files distributed with fio unless otherwise 7af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * noted in the file itself. 8af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * 9af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * This program is free software; you can redistribute it and/or modify 10af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * it under the terms of the GNU General Public License version 2 as 11af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * published by the Free Software Foundation. 12af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * 13af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * This program is distributed in the hope that it will be useful, 14af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * but WITHOUT ANY WARRANTY; without even the implied warranty of 15af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * GNU General Public License for more details. 17af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * 18af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * You should have received a copy of the GNU General Public License 19af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * along with this program; if not, write to the Free Software 20af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * 22af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron */ 23af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include <string.h> 24af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include <malloc.h> 25af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include <math.h> 26af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include <assert.h> 2793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe#include <stdlib.h> 28af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 29af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include <cairo.h> 30af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include <gtk/gtk.h> 31af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 32af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron#include "tickmarks.h" 3309ad20ff60eb8c11edf407c4060062dae187f5e7Stephen M. Cameron#include "graph.h" 34b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe#include "flist.h" 35b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe#include "lib/prio_tree.h" 36b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 37b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe/* 38b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * Allowable difference to show tooltip 39b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 40b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe#define TOOLTIP_DELTA 0.08 41af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 42af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct xyvalue { 43af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x, y; 44af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 45af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 46af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct graph_value { 47af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *next; 48b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_node node; 4993e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe char *tooltip; 50af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron void *value; 51af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 52af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 53af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct graph_label { 54af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *label; 55af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *tail; 56af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *values; 57af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *next; 58b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_root prio_tree; 59af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double r, g, b; 60af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int value_count; 6193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe unsigned int tooltip_count; 62af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph *parent; 63af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 64af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 65b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboestruct tick_value { 66b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe unsigned int offset; 67b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double value; 68b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe}; 69b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 70af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct graph { 71af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *title; 72af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *xtitle; 73af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *ytitle; 7487d5f276b14f42b09062d499ebb3f524e3aa86f3Jens Axboe unsigned int xdim, ydim; 7557f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron double xoffset, yoffset; 76af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *labels; 77af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *tail; 78af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int per_label_limit; 79f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe const char *font; 807175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron graph_axis_unit_change_callback x_axis_unit_change_callback; 817175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron graph_axis_unit_change_callback y_axis_unit_change_callback; 82d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe unsigned int base_offset; 83def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double left_extra; 84def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double right_extra; 85def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double top_extra; 86def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double bottom_extra; 87b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 88b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double xtick_zero; 89b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double xtick_delta; 90b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double xtick_zero_val; 91b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double xtick_one_val; 92b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double ytick_zero; 93b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double ytick_delta; 94b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double ytick_zero_val; 95b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double ytick_one_val; 96af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 97af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 983ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameronvoid graph_set_size(struct graph *g, unsigned int xdim, unsigned int ydim) 993ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron{ 1003ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron g->xdim = xdim; 1013ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron g->ydim = ydim; 1023ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron} 1033ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron 10457f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameronvoid graph_set_position(struct graph *g, double xoffset, double yoffset) 10557f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron{ 10657f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron g->xoffset = xoffset; 10757f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron g->yoffset = yoffset; 10857f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron} 10957f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron 110f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboestruct graph *graph_new(unsigned int xdim, unsigned int ydim, const char *font) 111af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 112af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph *g; 113af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 114af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron g = calloc(1, sizeof(*g)); 1153ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron graph_set_size(g, xdim, ydim); 116af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron g->per_label_limit = -1; 117f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe g->font = font; 118f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe if (!g->font) 119f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe g->font = "Sans"; 120af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return g; 121af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 122af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 1237175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameronvoid graph_x_axis_unit_change_notify(struct graph *g, graph_axis_unit_change_callback f) 1247175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron{ 1257175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->x_axis_unit_change_callback = f; 1267175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron} 1277175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron 1287175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameronvoid graph_y_axis_unit_change_notify(struct graph *g, graph_axis_unit_change_callback f) 1297175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron{ 1307175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->y_axis_unit_change_callback = f; 1317175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron} 1327175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron 133af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic int count_labels(struct graph_label *labels) 134af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 135af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int count = 0; 136af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 137af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 138af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = labels; i; i = i->next) 139af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron count++; 140af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return count; 141af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 142af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 143af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic int count_values(struct graph_value *values) 144af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 145af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int count = 0; 146af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *i; 147af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 148af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = values; i; i = i->next) 149af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron count++; 150af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return count; 151af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 152af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 153af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Camerontypedef double (*double_comparator)(double a, double b); 154af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 155af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double mindouble(double a, double b) 156af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 157af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return a < b ? a : b; 158af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 159af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 160af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double maxdouble(double a, double b) 161af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 162af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return a < b ? b : a; 163af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 164af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 165af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double find_double_values(struct graph_value *values, double_comparator cmp) 166af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 167af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *i; 168af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int first = 1; 169af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double answer, tmp; 170af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 171af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron assert(values != NULL); 172af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = 0.0; /* shut the compiler up, might need to think harder though. */ 173af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = values; i; i = i->next) { 174af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron tmp = *(double *) i->value; 175af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (first) { 176af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = tmp; 177af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 0; 178af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } else { 179af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = cmp(answer, tmp); 180af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 181af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 182af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return answer; 183af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 184af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 185af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double find_double_data(struct graph_label *labels, double_comparator cmp) 186af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 187af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 188af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int first = 1; 189af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double answer, tmp; 190af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 191af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron assert(labels != NULL); 192af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = 0.0; /* shut the compiler up, might need to think harder though. */ 193af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = labels; i; i = i->next) { 194af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron tmp = find_double_values(i->values, cmp); 195af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (first) { 196af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = tmp; 197af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 0; 198af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } else { 199af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = cmp(tmp, answer); 200af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 201af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 202af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return answer; 203af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 204af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 205af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double find_min_data(struct graph_label *labels) 206af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 207af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return find_double_data(labels, mindouble); 208af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 209af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 210af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double find_max_data(struct graph_label *labels) 211af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 212af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return find_double_data(labels, maxdouble); 213af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 214af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 215af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void draw_bars(struct graph *bg, cairo_t *cr, struct graph_label *lb, 216af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double label_offset, double bar_width, 217af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double mindata, double maxdata) 218af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 219af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *i; 220af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, y1, x2, y2; 221af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int bar_num = 0; 222af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double domain, range, v; 223af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 224af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron domain = (maxdata - mindata); 225af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron range = (double) bg->ydim * 0.80; /* FIXME */ 226af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 227af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = lb->values; i; i = i->next) { 228af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 229af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x1 = label_offset + (double) bar_num * bar_width + (bar_width * 0.05); 230af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x2 = x1 + bar_width * 0.90; 231af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y2 = bg->ydim * 0.90; 232af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron v = *(double *) i->value; 233af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y1 = y2 - (((v - mindata) / domain) * range); 234af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x1, y1); 235af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x1, y2); 236af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x2, y2); 237af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x2, y1); 238af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_close_path(cr); 239af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_fill(cr); 240af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 241af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bar_num++; 242af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 243af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 244af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 24510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic void draw_aligned_text(struct graph *g, cairo_t *cr, double x, double y, 24610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text, int alignment) 247af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 24810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron#define CENTERED 0 24910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron#define LEFT_JUSTIFIED 1 25010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron#define RIGHT_JUSTIFIED 2 25110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 25210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double factor, direction; 253af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents_t extents; 254af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 25510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron switch(alignment) { 25610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron case CENTERED: 25710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron direction = -1.0; 25810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron factor = 0.5; 25910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron break; 26010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron case RIGHT_JUSTIFIED: 26110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron direction = -1.0; 26210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron factor = 1.0; 26310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron break; 26410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron case LEFT_JUSTIFIED: 26510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron default: 26610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron direction = 1.0; 26710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron factor = 1.0; 26810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron break; 26910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron } 270f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_select_font_face (cr, g->font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 271af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 272af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_font_size(cr, fontsize); 273af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents(cr, text, &extents); 27410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron x = x + direction * (factor * extents.width + extents.x_bearing); 275af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y = y - (extents.height / 2 + extents.y_bearing); 276af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 277af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x, y); 278af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_show_text(cr, text); 279af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 280af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 28110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic inline void draw_centered_text(struct graph *g, cairo_t *cr, double x, double y, 28210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text) 28310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron{ 28410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_aligned_text(g, cr, x, y, fontsize, text, CENTERED); 28510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron} 28610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 28710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic inline void draw_right_justified_text(struct graph *g, cairo_t *cr, 28810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double x, double y, 28910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text) 29010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron{ 29110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_aligned_text(g, cr, x, y, fontsize, text, RIGHT_JUSTIFIED); 29210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron} 29310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 29410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic inline void draw_left_justified_text(struct graph *g, cairo_t *cr, 29510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double x, double y, 29610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text) 29710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron{ 29810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_aligned_text(g, cr, x, y, fontsize, text, LEFT_JUSTIFIED); 29910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron} 30010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 301f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboestatic void draw_vertical_centered_text(struct graph *g, cairo_t *cr, double x, 302f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe double y, double fontsize, 303f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe const char *text) 304af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 305af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double sx, sy; 306af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents_t extents; 307af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 308f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_select_font_face(cr, g->font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 309af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 310af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_font_size(cr, fontsize); 311af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents(cr, text, &extents); 312af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron sx = x; 313af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron sy = y; 314af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y = y + (extents.width / 2.0 + extents.x_bearing); 315af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x = x - (extents.height / 2.0 + extents.y_bearing); 316af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 317af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x, y); 318af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 319af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_translate(cr, -sx, -sy); 320af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_rotate(cr, -90.0 * M_PI / 180.0); 321af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_translate(cr, sx, sy); 322af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_show_text(cr, text); 323af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 324af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 325af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 326af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void graph_draw_common(struct graph *g, cairo_t *cr, 327af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double *x1, double *y1, double *x2, double *y2) 328af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 329af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_source_rgb(cr, 0, 0, 0); 330f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_set_line_width (cr, 0.8); 331af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 3329ede9c9c00f5457564677833cc44d436b7c936c4Jens Axboe *x1 = 0.10 * g->xdim; 3336bf860089760c72ea22bc74e929080c15cd4c835Stephen M. Cameron *x2 = 0.95 * g->xdim; 3346bf860089760c72ea22bc74e929080c15cd4c835Stephen M. Cameron *y1 = 0.10 * g->ydim; 3356bf860089760c72ea22bc74e929080c15cd4c835Stephen M. Cameron *y2 = 0.90 * g->ydim; 336af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 337af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, *x1, *y1); 338af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x1, *y2); 339af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x2, *y2); 340af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x2, *y1); 341af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x1, *y1); 342af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 343af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 344f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(g, cr, g->xdim / 2, g->ydim / 20, 20.0, g->title); 345f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(g, cr, g->xdim / 2, g->ydim * 0.97, 14.0, g->xtitle); 346f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_vertical_centered_text(g, cr, g->xdim * 0.02, g->ydim / 2, 14.0, g->ytitle); 347af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 348af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 349af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 350af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void graph_draw_x_ticks(struct graph *g, cairo_t *cr, 351af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, double y1, double x2, double y2, 352d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe double minx, double maxx, int nticks, int add_tm_text) 353af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 354af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct tickmark *tm; 355af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double tx; 3567175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron int i, power_of_ten; 357af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron static double dash[] = { 1.0, 2.0 }; 358af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 3597175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron nticks = calc_tickmarks(minx, maxx, nticks, &tm, &power_of_ten, 360d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe g->x_axis_unit_change_callback == NULL, g->base_offset); 3617175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron if (g->x_axis_unit_change_callback) 3627175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->x_axis_unit_change_callback(g, power_of_ten); 363af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 364af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = 0; i < nticks; i++) { 365af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron tx = (((tm[i].value) - minx) / (maxx - minx)) * (x2 - x1) + x1; 366d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 367b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe /* 368b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * Update tick delta 369b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 370b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!i) { 371b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->xtick_zero = tx; 372b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->xtick_zero_val = tm[0].value; 373b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } else if (i == 1) { 374b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->xtick_delta = (tm[1].value - tm[0].value) / (tx - g->xtick_zero); 375b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe g->xtick_one_val = tm[1].value; 376b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } 377b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 378d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* really tx < yx || tx > x2, but protect against rounding */ 379d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (x1 - tx > 0.01 || tx - x2 > 0.01) 380af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron continue; 381af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 382af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* Draw tick mark */ 383f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_set_line_width(cr, 0.8); 384af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, tx, y2); 385af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, tx, y2 + (y2 - y1) * 0.03); 386af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 387af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 388af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw grid lines */ 389af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 390af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_dash(cr, dash, 2, 2.0); 391af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_line_width(cr, 0.5); 392af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, tx, y1); 393af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, tx, y2); 394af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 395af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 396af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 397d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (!add_tm_text) 398d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe continue; 399d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 400af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw tickmark label */ 401f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(g, cr, tx, y2 * 1.04, 12.0, tm[i].string); 402af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 403af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 404af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 405af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 406d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboestatic double graph_draw_y_ticks(struct graph *g, cairo_t *cr, 407af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, double y1, double x2, double y2, 408d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe double miny, double maxy, int nticks, int add_tm_text) 409af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 410af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct tickmark *tm; 411af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double ty; 4127175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron int i, power_of_ten; 413af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron static double dash[] = { 2.0, 2.0 }; 414af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 4157175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron nticks = calc_tickmarks(miny, maxy, nticks, &tm, &power_of_ten, 416d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe g->y_axis_unit_change_callback == NULL, g->base_offset); 4177175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron if (g->y_axis_unit_change_callback) 4187175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->y_axis_unit_change_callback(g, power_of_ten); 419af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 420d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* 421d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * Use highest tickmark as top of graph, not highest value. Otherwise 422d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * it's impossible to see what the max value is, if the graph is 423d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * fairly flat. 424d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe */ 425d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe maxy = tm[nticks - 1].value; 426d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 427af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = 0; i < nticks; i++) { 428af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron ty = y2 - (((tm[i].value) - miny) / (maxy - miny)) * (y2 - y1); 429d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 430b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe /* 431b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * Update tick delta 432b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 433b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!i) { 434b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->ytick_zero = ty; 435b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->ytick_zero_val = tm[0].value; 436b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } else if (i == 1) { 437b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->ytick_delta = (tm[1].value - tm[0].value) / (ty - g->ytick_zero); 438b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe g->ytick_one_val = tm[1].value; 439b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } 440b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 441d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* really ty < y1 || ty > y2, but protect against rounding */ 442d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (y1 - ty > 0.01 || ty - y2 > 0.01) 443af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron continue; 444d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 445af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw tick mark */ 446af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x1, ty); 447af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x1 - (x2 - x1) * 0.02, ty); 448af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 449af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 450af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw grid lines */ 451af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 452af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_dash(cr, dash, 2, 2.0); 453af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_line_width(cr, 0.5); 454af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x1, ty); 455af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x2, ty); 456af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 457af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 458af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 459d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (!add_tm_text) 460d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe continue; 461d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 462af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw tickmark label */ 46310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_right_justified_text(g, cr, x1 - (x2 - x1) * 0.025, ty, 12.0, tm[i].string); 464af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 465af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 466d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 467d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* 468d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * Return new max to use 469d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe */ 470d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe return maxy; 471af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 472af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 473af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid bar_graph_draw(struct graph *bg, cairo_t *cr) 474af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 475af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, y1, x2, y2; 476af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double space_per_label, bar_width; 477af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double label_offset, mindata, maxdata; 478af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int i, nlabels; 479af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *lb; 480af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 481af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 48257f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron cairo_translate(cr, bg->xoffset, bg->yoffset); 483af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron graph_draw_common(bg, cr, &x1, &y1, &x2, &y2); 484af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 485af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron nlabels = count_labels(bg->labels); 486d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe space_per_label = (x2 - x1) / (double) nlabels; 487af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 488bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe /* 489bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe * Start bars at 0 unless we have negative values, otherwise we 490bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe * present a skewed picture comparing label X and X+1. 491bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe */ 492af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron mindata = find_min_data(bg->labels); 493bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe if (mindata > 0) 494bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe mindata = 0; 495bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe 496af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron maxdata = find_max_data(bg->labels); 497af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 498af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (fabs(maxdata - mindata) < 1e-20) { 499f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(bg, cr, 500af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x1 + (x2 - x1) / 2.0, 501af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y1 + (y2 - y1) / 2.0, 20.0, "No good data"); 502af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return; 503af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 504af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 505bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe maxdata = graph_draw_y_ticks(bg, cr, x1, y1, x2, y2, mindata, maxdata, 10, 1); 506af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = 0; 507af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (lb = bg->labels; lb; lb = lb->next) { 508af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int nvalues; 509af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron nvalues = count_values(lb->values); 510af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bar_width = (space_per_label - space_per_label * 0.2) / (double) nvalues; 511af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron label_offset = bg->xdim * 0.1 + space_per_label * (double) i + space_per_label * 0.1; 512af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron draw_bars(bg, cr, lb, label_offset, bar_width, mindata, maxdata); 513af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron // draw_centered_text(cr, label_offset + (bar_width / 2.0 + bar_width * 0.1), bg->ydim * 0.93, 514f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(bg, cr, x1 + space_per_label * (i + 0.5), bg->ydim * 0.93, 515af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 12.0, lb->label); 516af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i++; 517af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 518af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 519af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 520af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 521af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 522af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Camerontypedef double (*xy_value_extractor)(struct graph_value *v); 523af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 524af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double getx(struct graph_value *v) 525af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 526af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct xyvalue *xy = v->value; 527af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return xy->x; 528af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 529af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 530af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double gety(struct graph_value *v) 531af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 532af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct xyvalue *xy = v->value; 533af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return xy->y; 534af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 535af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 536af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double find_xy_value(struct graph *g, xy_value_extractor getvalue, double_comparator cmp) 537af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 53810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double tmp, answer = 0.0; 539af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 540af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *j; 541d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron int first = 1; 542af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 543af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = g->labels; i; i = i->next) 544af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (j = i->values; j; j = j->next) { 545af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron tmp = getvalue(j); 546d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron if (first) { 547d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron first = 0; 548d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron answer = tmp; 549d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron } 550af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = cmp(tmp, answer); 551af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 552af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return answer; 553af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 554af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 555af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid line_graph_draw(struct graph *g, cairo_t *cr) 556af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 557af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, y1, x2, y2; 558def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double minx, miny, maxx, maxy, gminx, gminy, gmaxx, gmaxy; 559def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double tx, ty, top_extra, bottom_extra, left_extra, right_extra; 560af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 561af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *j; 5629ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron int good_data = 1, first = 1; 563af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 564af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 56557f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron cairo_translate(cr, g->xoffset, g->yoffset); 566af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron graph_draw_common(g, cr, &x1, &y1, &x2, &y2); 567af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 568af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron minx = find_xy_value(g, getx, mindouble); 569af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron maxx = find_xy_value(g, getx, maxdouble); 570af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron miny = find_xy_value(g, gety, mindouble); 5715aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe 5725aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe /* 5735aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe * Start graphs at zero, unless we have a value below. Otherwise 5745aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe * it's hard to visually compare the read and write graph, since 5755aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe * the lowest valued one will be the floor of the graph view. 5765aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe */ 5775aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe if (miny > 0) 5785aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe miny = 0; 5795aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe 580af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron maxy = find_xy_value(g, gety, maxdouble); 581af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 582af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (fabs(maxx - minx) < 1e-20 || fabs(maxy - miny) < 1e-20) { 5839ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron good_data = 0; 5849ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron minx = 0.0; 5859ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron miny = 0.0; 5869ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron maxx = 10.0; 5879ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron maxy = 100.0; 588af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 589af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 590def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron top_extra = 0.0; 591def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron bottom_extra = 0.0; 592def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron left_extra = 0.0; 593def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron right_extra = 0.0; 594def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 595def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->top_extra > 0.001) 596def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron top_extra = fabs(maxy - miny) * g->top_extra; 597def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->bottom_extra > 0.001) 598def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron bottom_extra = fabs(maxy - miny) * g->bottom_extra; 599def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->left_extra > 0.001) 600def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron left_extra = fabs(maxx - minx) * g->left_extra; 601def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->right_extra > 0.001) 602def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron right_extra = fabs(maxx - minx) * g->right_extra; 603def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 604def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gminx = minx - left_extra; 605def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gmaxx = maxx + right_extra; 606def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gminy = miny - bottom_extra; 607def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gmaxy = maxy + top_extra; 608def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 609d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe graph_draw_x_ticks(g, cr, x1, y1, x2, y2, gminx, gmaxx, 10, good_data); 610d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe gmaxy = graph_draw_y_ticks(g, cr, x1, y1, x2, y2, gminy, gmaxy, 10, good_data); 611af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 6129ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron if (!good_data) 6139ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron goto skip_data; 6149ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron 615f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_set_line_width(cr, 1.5); 616af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = g->labels; i; i = i->next) { 617af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 1; 618cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (i->r < 0) /* invisible data */ 619cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron continue; 620b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 621af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_source_rgb(cr, i->r, i->g, i->b); 622af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (j = i->values; j; j = j->next) { 623def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron tx = ((getx(j) - gminx) / (gmaxx - gminx)) * (x2 - x1) + x1; 624def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron ty = y2 - ((gety(j) - gminy) / (gmaxy - gminy)) * (y2 - y1); 625af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (first) { 626af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, tx, ty); 627af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 0; 628af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } else { 629af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, tx, ty); 630af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 631af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 632af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 633af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 6349ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron 6359ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameronskip_data: 636af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 637af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 638af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 639af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void setstring(char **str, const char *value) 640af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 641b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(*str); 642af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron *str = strdup(value); 643af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 644af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 645af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_title(struct graph *bg, const char *title) 646af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 647af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&bg->title, title); 648af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 649af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 650af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_x_title(struct graph *bg, const char *title) 651af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 652af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&bg->xtitle, title); 653af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 654af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 655af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_y_title(struct graph *bg, const char *title) 656af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 657af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&bg->ytitle, title); 658af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 659af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 660af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic struct graph_label *graph_find_label(struct graph *bg, 661af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron const char *label) 662af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 663af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 664af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 665af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = bg->labels; i; i = i->next) 666af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (strcmp(label, i->label) == 0) 667af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return i; 668af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return NULL; 669af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 670af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 671af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_add_label(struct graph *bg, const char *label) 672af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 673af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 674af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 675af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = graph_find_label(bg, label); 676af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (i) 677af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return; /* already present. */ 678af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = calloc(1, sizeof(*i)); 679af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->parent = bg; 680af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&i->label, label); 681af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->next = NULL; 682af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (!bg->tail) 683af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bg->labels = i; 684af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron else 685af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bg->tail->next = i; 686af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bg->tail = i; 687b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe INIT_PRIO_TREE_ROOT(&i->prio_tree); 688af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 689af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 690b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboestatic void graph_label_add_value(struct graph_label *i, void *value, 691b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe const char *tooltip) 692af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 693b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe struct graph *g = i->parent; 694af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *x; 695af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 696af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x = malloc(sizeof(*x)); 6973ca30e63c16734837336380b6f40b85e97579167Jens Axboe memset(x, 0, sizeof(*x)); 698af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x->value = value; 699af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x->next = NULL; 700f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe if (!i->tail) 701af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->values = x; 702f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe else 703af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->tail->next = x; 704af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->tail = x; 705af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->value_count++; 706b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 707f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe if (tooltip) { 708b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe /* 709b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe * use msec to avoid dropping too much precision when 710b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe * storing as an integer. 711b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe */ 712b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double xval = getx(x); 713b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double minx = xval - (g->xtick_one_val * TOOLTIP_DELTA); 714b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double maxx = xval + (g->xtick_one_val * TOOLTIP_DELTA); 7154c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe struct prio_tree_node *ret; 716b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 717b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe xval = xval * 1000.0; 718b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe minx = minx * 1000.0; 719b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe maxx = maxx * 1000.0; 720b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe 7213ca30e63c16734837336380b6f40b85e97579167Jens Axboe INIT_PRIO_TREE_NODE(&x->node); 722b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.start = minx; 723b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.last = maxx; 724b552682725e8269e4977d3a11317ec27c1720ea2Jens Axboe if (x->node.last == x->node.start) { 725b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.last += fabs(g->xtick_delta); 726b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (x->node.last == x->node.start) 727b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.last++; 728b552682725e8269e4977d3a11317ec27c1720ea2Jens Axboe } 729b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 7304c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe /* 7314c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe * If ret != &x->node, we have an alias. Since the values 7324c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe * should be identical, we can drop it 7334c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe */ 7344c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe ret = prio_tree_insert(&i->prio_tree, &x->node); 735f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe if (ret == &x->node) { 736f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe x->tooltip = strdup(tooltip); 7374c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe i->tooltip_count++; 738f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe } 739b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } 740af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 741b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (g->per_label_limit != -1 && 742b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe i->value_count > g->per_label_limit) { 743c148daed3da130062a7575d5667ca0e044927153Jens Axboe int to_drop = 1; 744c148daed3da130062a7575d5667ca0e044927153Jens Axboe 745c148daed3da130062a7575d5667ca0e044927153Jens Axboe /* 746c148daed3da130062a7575d5667ca0e044927153Jens Axboe * If the limit was dynamically reduced, making us more 747c148daed3da130062a7575d5667ca0e044927153Jens Axboe * than 1 entry ahead after adding this one, drop two 748c148daed3da130062a7575d5667ca0e044927153Jens Axboe * entries. This will make us (eventually) reach the 749c148daed3da130062a7575d5667ca0e044927153Jens Axboe * specified limit. 750c148daed3da130062a7575d5667ca0e044927153Jens Axboe */ 751b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (i->value_count - g->per_label_limit >= 2) 752c148daed3da130062a7575d5667ca0e044927153Jens Axboe to_drop = 2; 753c148daed3da130062a7575d5667ca0e044927153Jens Axboe 754c148daed3da130062a7575d5667ca0e044927153Jens Axboe while (to_drop--) { 755c148daed3da130062a7575d5667ca0e044927153Jens Axboe x = i->values; 756c148daed3da130062a7575d5667ca0e044927153Jens Axboe i->values = i->values->next; 75793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe if (x->tooltip) { 75893e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe free(x->tooltip); 759b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe prio_tree_remove(&i->prio_tree, &x->node); 76093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe i->tooltip_count--; 76193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe } 762c148daed3da130062a7575d5667ca0e044927153Jens Axboe free(x->value); 763c148daed3da130062a7575d5667ca0e044927153Jens Axboe free(x); 764c148daed3da130062a7575d5667ca0e044927153Jens Axboe i->value_count--; 765c148daed3da130062a7575d5667ca0e044927153Jens Axboe } 766af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 767af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 768af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 769af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronint graph_add_data(struct graph *bg, const char *label, const double value) 770af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 771af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 772af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double *d; 773af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 774af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron d = malloc(sizeof(*d)); 775af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron *d = value; 776af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 777af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = graph_find_label(bg, label); 778af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (!i) 779af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return -1; 780b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe graph_label_add_value(i, d, NULL); 781af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return 0; 782af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 783af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 784af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronint graph_add_xy_data(struct graph *bg, const char *label, 78593e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe const double x, const double y, const char *tooltip) 786af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 787af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 788af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct xyvalue *xy; 789af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 790af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron xy = malloc(sizeof(*xy)); 791af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron xy->x = x; 792af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron xy->y = y; 793af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 794af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = graph_find_label(bg, label); 795af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (!i) 796af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return -1; 79793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 798b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe graph_label_add_value(i, xy, tooltip); 799af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return 0; 800af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 801af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 8023ca30e63c16734837336380b6f40b85e97579167Jens Axboestatic void graph_free_values(struct graph_label *l, struct graph_value *values) 803af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 804af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *i, *next; 805af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 806af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = values; i; i = next) { 807af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron next = i->next; 808b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(i->value); 8093ca30e63c16734837336380b6f40b85e97579167Jens Axboe if (i->tooltip) { 8103ca30e63c16734837336380b6f40b85e97579167Jens Axboe free(i->tooltip); 8113ca30e63c16734837336380b6f40b85e97579167Jens Axboe prio_tree_remove(&l->prio_tree, &i->node); 8123ca30e63c16734837336380b6f40b85e97579167Jens Axboe l->tooltip_count--; 8133ca30e63c16734837336380b6f40b85e97579167Jens Axboe } 814b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(i); 815af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 816af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 817af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 818af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void graph_free_labels(struct graph_label *labels) 819af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 820af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i, *next; 821af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 822af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = labels; i; i = next) { 823af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron next = i->next; 8243ca30e63c16734837336380b6f40b85e97579167Jens Axboe graph_free_values(i, i->values); 825b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(i); 826af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 827af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 828af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 829af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_set_color(struct graph *gr, const char *label, 830af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double red, double green, double blue) 831af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 832af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 833af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double r, g, b; 834af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 835cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (red < 0.0) { /* invisible color */ 836cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron r = -1.0; 837cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron g = -1.0; 838cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron b = -1.0; 839cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron } else { 840cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron r = fabs(red); 841cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron g = fabs(green); 842cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron b = fabs(blue); 843cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron 844cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (r > 1.0) 845cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron r = 1.0; 846cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (g > 1.0) 847cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron g = 1.0; 848cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (b > 1.0) 849b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe b = 1.0; 850cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron } 851af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 852af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = gr->labels; i; i = i->next) 853af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (strcmp(i->label, label) == 0) { 854af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->r = r; 855af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->g = g; 856af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->b = b; 857af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron break; 858af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 859af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 860af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 861af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_free(struct graph *bg) 862af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 863b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(bg->title); 864b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(bg->xtitle); 865b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(bg->ytitle); 866af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron graph_free_labels(bg->labels); 867af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 868af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 869af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron/* For each line in the line graph, up to per_label_limit segments may 870af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * be added. After that, adding more data to the end of the line 871af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * causes data to drop off of the front of the line. 872af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron */ 873af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid line_graph_set_data_count_limit(struct graph *g, int per_label_limit) 874af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 875af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron g->per_label_limit = per_label_limit; 876af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 877af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 878def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameronvoid graph_add_extra_space(struct graph *g, double left_percent, double right_percent, 879def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double top_percent, double bottom_percent) 880def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron{ 881def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->left_extra = left_percent; 882def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->right_extra = right_percent; 883def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->top_extra = top_percent; 884def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->bottom_extra = bottom_percent; 885def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron} 886def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 887d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe/* 888d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * Normally values are logged in a base unit of 0, but for other purposes 889d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * it makes more sense to log in higher unit. For instance for bandwidth 890d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * purposes, you may want to log in KB/sec (or MB/sec) rather than bytes/sec. 891d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe */ 892d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboevoid graph_set_base_offset(struct graph *g, unsigned int base_offset) 893d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe{ 894d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe g->base_offset = base_offset; 895d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe} 896d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 89793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboeint graph_has_tooltips(struct graph *g) 89893e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe{ 89993e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe struct graph_label *i; 90093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 90193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe for (i = g->labels; i; i = i->next) 90293e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe if (i->tooltip_count) 90393e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return 1; 90493e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 90593e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return 0; 90693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe} 90793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 90893e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboeint graph_contains_xy(struct graph *g, int x, int y) 90993e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe{ 91093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int first_x = g->xoffset; 91193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int last_x = g->xoffset + g->xdim; 91293e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int first_y = g->yoffset; 91393e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int last_y = g->yoffset + g->ydim; 91493e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 91593e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return (x >= first_x && x <= last_x) && (y >= first_y && y <= last_y); 91693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe} 917def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 918b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboeconst char *graph_find_tooltip(struct graph *g, int ix, int iy) 91993e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe{ 920b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double x = ix, y = iy; 921b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_iter iter; 922b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_node *n; 923b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct graph_label *i; 924b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct graph_value *best = NULL; 925b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double best_delta; 926b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double maxy, miny; 92793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 928b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe x -= g->xoffset; 929b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe y -= g->yoffset; 93093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 931b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe x = g->xtick_zero_val + ((x - g->xtick_zero) * g->xtick_delta); 932b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe y = g->ytick_zero_val + ((y - g->ytick_zero) * g->ytick_delta); 93393e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 934b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x = x * 1000.0; 935b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe maxy = y + (g->ytick_one_val * TOOLTIP_DELTA); 936b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe miny = y - (g->ytick_one_val * TOOLTIP_DELTA); 937b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe best_delta = UINT_MAX; 938b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe i = g->labels; 939b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe do { 94008d7d5a80f3698f9a5b362831762c23e99fd9a22Jens Axboe INIT_PRIO_TREE_ITER(&iter); 941b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe prio_tree_iter_init(&iter, &i->prio_tree, x, x); 942b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 943b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe n = prio_tree_next(&iter); 944b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!n) 945b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe continue; 946b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 947b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe do { 948b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct graph_value *v; 949b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double yval, ydiff; 950b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 951b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe v = container_of(n, struct graph_value, node); 952b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe yval = gety(v); 953b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe ydiff = fabs(yval - y); 9540deba507cd01601fcce4fb861b9aa6d4971dfd1aJens Axboe 9550deba507cd01601fcce4fb861b9aa6d4971dfd1aJens Axboe /* 956b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * zero delta, or within or match critera, break 9570deba507cd01601fcce4fb861b9aa6d4971dfd1aJens Axboe */ 958b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (ydiff < best_delta) { 959b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe best_delta = ydiff; 960b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!best_delta || 961b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe (yval >= miny && yval <= maxy)) { 962b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe best = v; 963b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe break; 964b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } 965b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } 966b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } while ((n = prio_tree_next(&iter)) != NULL); 967b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 968b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe /* 969b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * If we got matches in one label, don't check others. 970b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 971b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe break; 972b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } while ((i = i->next) != NULL); 973b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 974b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (best) 975b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe return best->tooltip; 97693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 97793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return NULL; 97893e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe} 979