graph.c revision a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2
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 46cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboeenum { 47cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe GV_F_ON_PRIO = 1, 488dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe GV_F_PRIO_SKIP = 2, 49cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe}; 50cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 51af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct graph_value { 52cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head list; 53b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_node node; 54cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head alias; 55cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe unsigned int flags; 5693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe char *tooltip; 57af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron void *value; 58af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 59af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 60af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct graph_label { 61cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head list; 62af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *label; 63cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head value_list; 64b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_root prio_tree; 65af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double r, g, b; 6601a947f067b1a03add33e645ece73ac19d8257ddJens Axboe int hide; 67af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int value_count; 68af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph *parent; 69af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 70af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 71b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboestruct tick_value { 72b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe unsigned int offset; 73b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double value; 74b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe}; 75b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 76af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstruct graph { 77af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *title; 78af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *xtitle; 79af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron char *ytitle; 8087d5f276b14f42b09062d499ebb3f524e3aa86f3Jens Axboe unsigned int xdim, ydim; 8157f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron double xoffset, yoffset; 82cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head label_list; 83af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int per_label_limit; 84f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe const char *font; 857175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron graph_axis_unit_change_callback x_axis_unit_change_callback; 867175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron graph_axis_unit_change_callback y_axis_unit_change_callback; 87d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe unsigned int base_offset; 8801a947f067b1a03add33e645ece73ac19d8257ddJens Axboe unsigned int dont_graph_all_zeroes; 89def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double left_extra; 90def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double right_extra; 91def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double top_extra; 92def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double bottom_extra; 93b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 94b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double xtick_zero; 95b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double xtick_delta; 96b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double xtick_zero_val; 97b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double xtick_one_val; 98b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double ytick_zero; 99b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double ytick_delta; 100b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double ytick_zero_val; 101b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double ytick_one_val; 102af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron}; 103af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 1043ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameronvoid graph_set_size(struct graph *g, unsigned int xdim, unsigned int ydim) 1053ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron{ 1063ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron g->xdim = xdim; 1073ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron g->ydim = ydim; 1083ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron} 1093ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron 11057f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameronvoid graph_set_position(struct graph *g, double xoffset, double yoffset) 11157f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron{ 11257f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron g->xoffset = xoffset; 11357f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron g->yoffset = yoffset; 11457f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron} 11557f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron 116f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboestruct graph *graph_new(unsigned int xdim, unsigned int ydim, const char *font) 117af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 118af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph *g; 119af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 120af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron g = calloc(1, sizeof(*g)); 121cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe INIT_FLIST_HEAD(&g->label_list); 1223ea48b883bcac5ad0c119205805b741af45427e3Stephen M. Cameron graph_set_size(g, xdim, ydim); 123af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron g->per_label_limit = -1; 124f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe g->font = font; 125f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe if (!g->font) 126a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboe g->font = GRAPH_DEFAULT_FONT; 127af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return g; 128af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 129af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 130a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboevoid graph_set_font(struct graph *g, const char *font) 131a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboe{ 132a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboe g->font = font; 133a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboe} 134a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboe 1357175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameronvoid graph_x_axis_unit_change_notify(struct graph *g, graph_axis_unit_change_callback f) 1367175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron{ 1377175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->x_axis_unit_change_callback = f; 1387175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron} 1397175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron 1407175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameronvoid graph_y_axis_unit_change_notify(struct graph *g, graph_axis_unit_change_callback f) 1417175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron{ 1427175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->y_axis_unit_change_callback = f; 1437175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron} 1447175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron 145cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic int count_labels(struct graph *g) 146af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 147cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 148af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int count = 0; 149af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 150cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &g->label_list) 151af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron count++; 152cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 153af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return count; 154af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 155af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 156cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic int count_values(struct graph_label *l) 157af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 158cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 159af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int count = 0; 160af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 161cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &l->value_list) 162af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron count++; 163cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 164af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return count; 165af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 166af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 167af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Camerontypedef double (*double_comparator)(double a, double b); 168af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 169af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double mindouble(double a, double b) 170af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 171af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return a < b ? a : b; 172af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 173af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 174af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double maxdouble(double a, double b) 175af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 176af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return a < b ? b : a; 177af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 178af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 179cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic double find_double_values(struct graph_label *l, double_comparator cmp) 180af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 181cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 182af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double answer, tmp; 183cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe int first = 1; 184af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 18501a947f067b1a03add33e645ece73ac19d8257ddJens Axboe if (flist_empty(&l->value_list)) 18601a947f067b1a03add33e645ece73ac19d8257ddJens Axboe return 0.0; 18701a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 188cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &l->value_list) { 189cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_value *i; 190cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 191cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_value, list); 192cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe tmp = *(double *) i->value; 193af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (first) { 194af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = tmp; 195af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 0; 196af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } else { 197af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = cmp(answer, tmp); 198af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 199af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 200af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return answer; 201af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 202af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 203cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic double find_double_data(struct graph *g, double_comparator cmp) 204af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 205cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 206af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 207af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int first = 1; 208af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double answer, tmp; 209af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 21001a947f067b1a03add33e645ece73ac19d8257ddJens Axboe if (flist_empty(&g->label_list)) 21101a947f067b1a03add33e645ece73ac19d8257ddJens Axboe return 0.0; 21201a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 213cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &g->label_list) { 214cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_label, list); 215cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe tmp = find_double_values(i, cmp); 216af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (first) { 217af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = tmp; 218af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 0; 219af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } else { 220af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = cmp(tmp, answer); 221af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 222af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 223af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return answer; 224af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 225af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 226cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic double find_min_data(struct graph *g) 227af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 228cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe return find_double_data(g, mindouble); 229af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 230af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 231cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic double find_max_data(struct graph *g) 232af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 233cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe return find_double_data(g, maxdouble); 234af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 235af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 236af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void draw_bars(struct graph *bg, cairo_t *cr, struct graph_label *lb, 237af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double label_offset, double bar_width, 238af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double mindata, double maxdata) 239af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 240cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 241af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, y1, x2, y2; 242af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int bar_num = 0; 243af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double domain, range, v; 244af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 245af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron domain = (maxdata - mindata); 246af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron range = (double) bg->ydim * 0.80; /* FIXME */ 247af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 248cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &lb->value_list) { 249cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_value *i; 250cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 251cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_value, list); 252af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 253af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x1 = label_offset + (double) bar_num * bar_width + (bar_width * 0.05); 254af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x2 = x1 + bar_width * 0.90; 255af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y2 = bg->ydim * 0.90; 256af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron v = *(double *) i->value; 257af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y1 = y2 - (((v - mindata) / domain) * range); 258af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x1, y1); 259af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x1, y2); 260af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x2, y2); 261af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x2, y1); 262af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_close_path(cr); 263af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_fill(cr); 264af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 265af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bar_num++; 266af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 267af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 268af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 26910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic void draw_aligned_text(struct graph *g, cairo_t *cr, double x, double y, 27010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text, int alignment) 271af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 27210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron#define CENTERED 0 27310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron#define LEFT_JUSTIFIED 1 27410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron#define RIGHT_JUSTIFIED 2 27510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 27610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double factor, direction; 277af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents_t extents; 278af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 27910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron switch(alignment) { 28010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron case CENTERED: 28110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron direction = -1.0; 28210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron factor = 0.5; 28310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron break; 28410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron case RIGHT_JUSTIFIED: 28510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron direction = -1.0; 28610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron factor = 1.0; 28710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron break; 28810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron case LEFT_JUSTIFIED: 28910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron default: 29010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron direction = 1.0; 29110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron factor = 1.0; 29210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron break; 29310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron } 294a1e7972d96ce1482aa43c2fcafd81d6c7f3c44d2Jens Axboe cairo_select_font_face(cr, g->font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 295af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 296af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_font_size(cr, fontsize); 297af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents(cr, text, &extents); 29810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron x = x + direction * (factor * extents.width + extents.x_bearing); 299af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y = y - (extents.height / 2 + extents.y_bearing); 300af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 301af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x, y); 302af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_show_text(cr, text); 303af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 304af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 30510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic inline void draw_centered_text(struct graph *g, cairo_t *cr, double x, double y, 30610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text) 30710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron{ 30810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_aligned_text(g, cr, x, y, fontsize, text, CENTERED); 30910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron} 31010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 31110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic inline void draw_right_justified_text(struct graph *g, cairo_t *cr, 31210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double x, double y, 31310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text) 31410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron{ 31510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_aligned_text(g, cr, x, y, fontsize, text, RIGHT_JUSTIFIED); 31610e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron} 31710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 31810e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameronstatic inline void draw_left_justified_text(struct graph *g, cairo_t *cr, 31910e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double x, double y, 32010e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double fontsize, const char *text) 32110e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron{ 32210e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_aligned_text(g, cr, x, y, fontsize, text, LEFT_JUSTIFIED); 32310e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron} 32410e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron 325f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboestatic void draw_vertical_centered_text(struct graph *g, cairo_t *cr, double x, 326f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe double y, double fontsize, 327f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe const char *text) 328af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 329af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double sx, sy; 330af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents_t extents; 331af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 332f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_select_font_face(cr, g->font, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); 333af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 334af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_font_size(cr, fontsize); 335af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_text_extents(cr, text, &extents); 336af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron sx = x; 337af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron sy = y; 338af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y = y + (extents.width / 2.0 + extents.x_bearing); 339af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x = x - (extents.height / 2.0 + extents.y_bearing); 340af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 341af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x, y); 342af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 343af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_translate(cr, -sx, -sy); 344af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_rotate(cr, -90.0 * M_PI / 180.0); 345af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_translate(cr, sx, sy); 346af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_show_text(cr, text); 347af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 348af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 349af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 350af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void graph_draw_common(struct graph *g, cairo_t *cr, 351af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double *x1, double *y1, double *x2, double *y2) 352af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 3534e14f0181e1c0cc59a55601011ba7bc73e4c5b20Jens Axboe cairo_set_source_rgb(cr, 0, 0, 0); 3544e14f0181e1c0cc59a55601011ba7bc73e4c5b20Jens Axboe cairo_set_line_width (cr, 0.8); 355af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 3569ede9c9c00f5457564677833cc44d436b7c936c4Jens Axboe *x1 = 0.10 * g->xdim; 3576bf860089760c72ea22bc74e929080c15cd4c835Stephen M. Cameron *x2 = 0.95 * g->xdim; 3586bf860089760c72ea22bc74e929080c15cd4c835Stephen M. Cameron *y1 = 0.10 * g->ydim; 3596bf860089760c72ea22bc74e929080c15cd4c835Stephen M. Cameron *y2 = 0.90 * g->ydim; 360af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 361af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, *x1, *y1); 362af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x1, *y2); 363af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x2, *y2); 364af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x2, *y1); 365af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, *x1, *y1); 366af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 367af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 368f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(g, cr, g->xdim / 2, g->ydim / 20, 20.0, g->title); 369f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(g, cr, g->xdim / 2, g->ydim * 0.97, 14.0, g->xtitle); 370f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_vertical_centered_text(g, cr, g->xdim * 0.02, g->ydim / 2, 14.0, g->ytitle); 371af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 372af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 373af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 374af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void graph_draw_x_ticks(struct graph *g, cairo_t *cr, 375af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, double y1, double x2, double y2, 376d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe double minx, double maxx, int nticks, int add_tm_text) 377af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 378af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct tickmark *tm; 379af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double tx; 3807175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron int i, power_of_ten; 381af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron static double dash[] = { 1.0, 2.0 }; 382af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 3837175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron nticks = calc_tickmarks(minx, maxx, nticks, &tm, &power_of_ten, 384d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe g->x_axis_unit_change_callback == NULL, g->base_offset); 3857175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron if (g->x_axis_unit_change_callback) 3867175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->x_axis_unit_change_callback(g, power_of_ten); 387af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 388af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = 0; i < nticks; i++) { 389af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron tx = (((tm[i].value) - minx) / (maxx - minx)) * (x2 - x1) + x1; 390d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 391b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe /* 392b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * Update tick delta 393b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 394b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!i) { 395b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->xtick_zero = tx; 396b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->xtick_zero_val = tm[0].value; 397b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } else if (i == 1) { 398b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->xtick_delta = (tm[1].value - tm[0].value) / (tx - g->xtick_zero); 399b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe g->xtick_one_val = tm[1].value; 400b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } 401b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 402d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* really tx < yx || tx > x2, but protect against rounding */ 403d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (x1 - tx > 0.01 || tx - x2 > 0.01) 404af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron continue; 405af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 406af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* Draw tick mark */ 407f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_set_line_width(cr, 0.8); 408af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, tx, y2); 409af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, tx, y2 + (y2 - y1) * 0.03); 410af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 411af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 412af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw grid lines */ 413af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 414af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_dash(cr, dash, 2, 2.0); 415af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_line_width(cr, 0.5); 416af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, tx, y1); 417af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, tx, y2); 418af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 419af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 420af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 421d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (!add_tm_text) 422d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe continue; 423d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 424af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw tickmark label */ 425f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(g, cr, tx, y2 * 1.04, 12.0, tm[i].string); 426af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 427af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 428af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 429af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 430d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboestatic double graph_draw_y_ticks(struct graph *g, cairo_t *cr, 431af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, double y1, double x2, double y2, 432d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe double miny, double maxy, int nticks, int add_tm_text) 433af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 434af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct tickmark *tm; 435af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double ty; 4367175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron int i, power_of_ten; 437af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron static double dash[] = { 2.0, 2.0 }; 438af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 4397175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron nticks = calc_tickmarks(miny, maxy, nticks, &tm, &power_of_ten, 440d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe g->y_axis_unit_change_callback == NULL, g->base_offset); 4417175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron if (g->y_axis_unit_change_callback) 4427175d91deff20b1408450c231b2b445ea28f7f29Stephen M. Cameron g->y_axis_unit_change_callback(g, power_of_ten); 443af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 444d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* 445d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * Use highest tickmark as top of graph, not highest value. Otherwise 446d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * it's impossible to see what the max value is, if the graph is 447d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * fairly flat. 448d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe */ 449d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe maxy = tm[nticks - 1].value; 450d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 451af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron for (i = 0; i < nticks; i++) { 452af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron ty = y2 - (((tm[i].value) - miny) / (maxy - miny)) * (y2 - y1); 453d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 454b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe /* 455b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * Update tick delta 456b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 457b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!i) { 458b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->ytick_zero = ty; 459b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->ytick_zero_val = tm[0].value; 460b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } else if (i == 1) { 461b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe g->ytick_delta = (tm[1].value - tm[0].value) / (ty - g->ytick_zero); 462b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe g->ytick_one_val = tm[1].value; 463b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe } 464b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 465d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* really ty < y1 || ty > y2, but protect against rounding */ 466d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (y1 - ty > 0.01 || ty - y2 > 0.01) 467af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron continue; 468d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 469af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw tick mark */ 470af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x1, ty); 471af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x1 - (x2 - x1) * 0.02, ty); 472af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 473af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 474af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw grid lines */ 475af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 476af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_dash(cr, dash, 2, 2.0); 477af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_line_width(cr, 0.5); 478af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, x1, ty); 479af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, x2, ty); 480af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 481af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 482af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 483d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe if (!add_tm_text) 484d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe continue; 485d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 486af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron /* draw tickmark label */ 48710e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron draw_right_justified_text(g, cr, x1 - (x2 - x1) * 0.025, ty, 12.0, tm[i].string); 488af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 489af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 490d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 491d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe /* 492d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * Return new max to use 493d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe */ 494d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe return maxy; 495af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 496af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 497af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid bar_graph_draw(struct graph *bg, cairo_t *cr) 498af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 499af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, y1, x2, y2; 500af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double space_per_label, bar_width; 501af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double label_offset, mindata, maxdata; 502af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int i, nlabels; 503af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *lb; 504cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 505af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 506af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 50757f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron cairo_translate(cr, bg->xoffset, bg->yoffset); 508af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron graph_draw_common(bg, cr, &x1, &y1, &x2, &y2); 509af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 510cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe nlabels = count_labels(bg); 511d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe space_per_label = (x2 - x1) / (double) nlabels; 512af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 513bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe /* 514bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe * Start bars at 0 unless we have negative values, otherwise we 515bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe * present a skewed picture comparing label X and X+1. 516bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe */ 517cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe mindata = find_min_data(bg); 518bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe if (mindata > 0) 519bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe mindata = 0; 520bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe 521cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe maxdata = find_max_data(bg); 522af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 523af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (fabs(maxdata - mindata) < 1e-20) { 524f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(bg, cr, 525af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x1 + (x2 - x1) / 2.0, 526af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron y1 + (y2 - y1) / 2.0, 20.0, "No good data"); 527af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return; 528af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 529af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 530bb39379fa3eb5e5c42c68e2e146561c49e3309f2Jens Axboe maxdata = graph_draw_y_ticks(bg, cr, x1, y1, x2, y2, mindata, maxdata, 10, 1); 531af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = 0; 532cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &bg->label_list) { 533af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron int nvalues; 534cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 535cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe lb = flist_entry(entry, struct graph_label, list); 536cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe nvalues = count_values(lb); 537af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron bar_width = (space_per_label - space_per_label * 0.2) / (double) nvalues; 538af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron label_offset = bg->xdim * 0.1 + space_per_label * (double) i + space_per_label * 0.1; 539af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron draw_bars(bg, cr, lb, label_offset, bar_width, mindata, maxdata); 540af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron // draw_centered_text(cr, label_offset + (bar_width / 2.0 + bar_width * 0.1), bg->ydim * 0.93, 541f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe draw_centered_text(bg, cr, x1 + space_per_label * (i + 0.5), bg->ydim * 0.93, 542af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 12.0, lb->label); 543af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i++; 544af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 545af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 546af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 547af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 548af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 549af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Camerontypedef double (*xy_value_extractor)(struct graph_value *v); 550af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 551af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double getx(struct graph_value *v) 552af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 553af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct xyvalue *xy = v->value; 554af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return xy->x; 555af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 556af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 557af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double gety(struct graph_value *v) 558af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 559af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct xyvalue *xy = v->value; 560af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return xy->y; 561af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 562af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 563af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic double find_xy_value(struct graph *g, xy_value_extractor getvalue, double_comparator cmp) 564af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 56510e54cdcc78dc173ee5ce4ee20cfd4f5fef97173Stephen M. Cameron double tmp, answer = 0.0; 566af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 567af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *j; 568cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *jentry, *entry; 569d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron int first = 1; 570af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 571cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &g->label_list) { 572cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_label, list); 573cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 574cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(jentry, &i->value_list) { 575cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe j = flist_entry(jentry, struct graph_value, list); 576af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron tmp = getvalue(j); 577d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron if (first) { 578d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron first = 0; 579d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron answer = tmp; 580d582bf70449c1ebbd96f9afa3b2e37dcc7dfb11fStephen M. Cameron } 581af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron answer = cmp(tmp, answer); 582af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 583cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 584cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 585af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return answer; 58601a947f067b1a03add33e645ece73ac19d8257ddJens Axboe} 587af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 588af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid line_graph_draw(struct graph *g, cairo_t *cr) 589af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 590af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double x1, y1, x2, y2; 591def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double minx, miny, maxx, maxy, gminx, gminy, gmaxx, gmaxy; 592def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double tx, ty, top_extra, bottom_extra, left_extra, right_extra; 593af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 594af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *j; 5959ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron int good_data = 1, first = 1; 596cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry, *lentry; 597af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 598af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_save(cr); 59957f9d28e010b52fea5f41245e8fcb998367d3bcdStephen M. Cameron cairo_translate(cr, g->xoffset, g->yoffset); 600af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron graph_draw_common(g, cr, &x1, &y1, &x2, &y2); 601af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 602af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron minx = find_xy_value(g, getx, mindouble); 603af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron maxx = find_xy_value(g, getx, maxdouble); 604af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron miny = find_xy_value(g, gety, mindouble); 6055aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe 6065aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe /* 6075aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe * Start graphs at zero, unless we have a value below. Otherwise 6085aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe * it's hard to visually compare the read and write graph, since 6095aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe * the lowest valued one will be the floor of the graph view. 6105aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe */ 6115aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe if (miny > 0) 6125aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe miny = 0; 6135aec66804d2a6d60aee8d973680c69b13c1d34a3Jens Axboe 614af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron maxy = find_xy_value(g, gety, maxdouble); 615af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 616af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (fabs(maxx - minx) < 1e-20 || fabs(maxy - miny) < 1e-20) { 6179ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron good_data = 0; 6189ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron minx = 0.0; 6199ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron miny = 0.0; 6209ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron maxx = 10.0; 6219ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron maxy = 100.0; 622af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 623af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 624def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron top_extra = 0.0; 625def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron bottom_extra = 0.0; 626def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron left_extra = 0.0; 627def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron right_extra = 0.0; 628def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 629def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->top_extra > 0.001) 630def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron top_extra = fabs(maxy - miny) * g->top_extra; 631def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->bottom_extra > 0.001) 632def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron bottom_extra = fabs(maxy - miny) * g->bottom_extra; 633def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->left_extra > 0.001) 634def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron left_extra = fabs(maxx - minx) * g->left_extra; 635def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron if (g->right_extra > 0.001) 636def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron right_extra = fabs(maxx - minx) * g->right_extra; 637def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 638def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gminx = minx - left_extra; 639def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gmaxx = maxx + right_extra; 640def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gminy = miny - bottom_extra; 641def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron gmaxy = maxy + top_extra; 642def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 643d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe graph_draw_x_ticks(g, cr, x1, y1, x2, y2, gminx, gmaxx, 10, good_data); 644d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe gmaxy = graph_draw_y_ticks(g, cr, x1, y1, x2, y2, gminy, gmaxy, 10, good_data); 645af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 6469ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron if (!good_data) 6479ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron goto skip_data; 6489ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron 649f3e8440f75f98ced28cdd19ba785718e734cf7c5Jens Axboe cairo_set_line_width(cr, 1.5); 650cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(lentry, &g->label_list) { 651cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(lentry, struct graph_label, list); 652af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 1; 65301a947f067b1a03add33e645ece73ac19d8257ddJens Axboe if (i->hide || i->r < 0) /* invisible data */ 654cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron continue; 655b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 656af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_set_source_rgb(cr, i->r, i->g, i->b); 657cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &i->value_list) { 658cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe j = flist_entry(entry, struct graph_value, list); 659def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron tx = ((getx(j) - gminx) / (gmaxx - gminx)) * (x2 - x1) + x1; 660def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron ty = y2 - ((gety(j) - gminy) / (gmaxy - gminy)) * (y2 - y1); 661af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (first) { 662af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_move_to(cr, tx, ty); 663af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron first = 0; 664af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } else { 665af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_line_to(cr, tx, ty); 666af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 667af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 668af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_stroke(cr); 669af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 6709ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameron 6719ce9cfbd6ab2a821aa31cedf64ec3e8c0729a4fcStephen M. Cameronskip_data: 672af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron cairo_restore(cr); 673af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 674af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 675af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic void setstring(char **str, const char *value) 676af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 677b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(*str); 678af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron *str = strdup(value); 679af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 680af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 681af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_title(struct graph *bg, const char *title) 682af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 683af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&bg->title, title); 684af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 685af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 686af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_x_title(struct graph *bg, const char *title) 687af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 688af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&bg->xtitle, title); 689af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 690af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 691af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_y_title(struct graph *bg, const char *title) 692af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 693af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&bg->ytitle, title); 694af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 695af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 696af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronstatic struct graph_label *graph_find_label(struct graph *bg, 697af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron const char *label) 698af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 699cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 700af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 701af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 702cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &bg->label_list) { 703cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_label, list); 704cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 705af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (strcmp(label, i->label) == 0) 706af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return i; 707cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 708cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 709af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return NULL; 710af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 711af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 7128dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboegraph_label_t graph_add_label(struct graph *bg, const char *label) 713af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 714af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_label *i; 715af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 716af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = graph_find_label(bg, label); 717af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron if (i) 7188dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe return i; /* already present. */ 719af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i = calloc(1, sizeof(*i)); 720cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe INIT_FLIST_HEAD(&i->value_list); 721af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->parent = bg; 722af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron setstring(&i->label, label); 723cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_add_tail(&i->list, &bg->label_list); 724b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe INIT_PRIO_TREE_ROOT(&i->prio_tree); 7258dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe return i; 726af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 727af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 728cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic void __graph_value_drop(struct graph_label *l, struct graph_value *v) 729cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe{ 730d0db819d9c5abe904f85a3b21a95023fef007f20Jens Axboe flist_del_init(&v->list); 731cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (v->tooltip) 732cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe free(v->tooltip); 733cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe free(v->value); 734cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe free(v); 735cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe l->value_count--; 736cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe} 737cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 738cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic void graph_value_drop(struct graph_label *l, struct graph_value *v) 739cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe{ 7408dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe if (v->flags & GV_F_PRIO_SKIP) { 7418dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe __graph_value_drop(l, v); 7428dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe return; 7438dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe } 7448dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe 745cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe /* 746cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe * Find head, the guy that's on the prio tree 747cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe */ 748cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe while (!(v->flags & GV_F_ON_PRIO)) { 749cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe assert(!flist_empty(&v->alias)); 750cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe v = flist_entry(v->alias.next, struct graph_value, alias); 751cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 752cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 753cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe prio_tree_remove(&l->prio_tree, &v->node); 754cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 755cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe /* 756cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe * Free aliases 757cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe */ 758d0db819d9c5abe904f85a3b21a95023fef007f20Jens Axboe while (!flist_empty(&v->alias)) { 759cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_value *a; 760cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 761d0db819d9c5abe904f85a3b21a95023fef007f20Jens Axboe a = flist_entry(v->alias.next, struct graph_value, alias); 762d0db819d9c5abe904f85a3b21a95023fef007f20Jens Axboe flist_del_init(&a->alias); 763cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 764cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe __graph_value_drop(l, a); 765cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 766cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 767cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe __graph_value_drop(l, v); 768cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe} 769cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 770b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboestatic void graph_label_add_value(struct graph_label *i, void *value, 771b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe const char *tooltip) 772af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 773b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe struct graph *g = i->parent; 774af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct graph_value *x; 775af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 776af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron x = malloc(sizeof(*x)); 7773ca30e63c16734837336380b6f40b85e97579167Jens Axboe memset(x, 0, sizeof(*x)); 778cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe INIT_FLIST_HEAD(&x->alias); 779cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe INIT_FLIST_HEAD(&x->list); 780cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_add_tail(&x->list, &i->value_list); 781af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron i->value_count++; 782cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe x->value = value; 783b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 784f00e43f2953d71cfc0fb21d704a473632d0b1ee4Jens Axboe if (tooltip) { 785b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double xval = getx(x); 786b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double minx = xval - (g->xtick_one_val * TOOLTIP_DELTA); 787b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double maxx = xval + (g->xtick_one_val * TOOLTIP_DELTA); 7884c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe struct prio_tree_node *ret; 789b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 7905fb8d7912ebf6fabb9ad3a61c4cd316126af602eJens Axboe /* 7915fb8d7912ebf6fabb9ad3a61c4cd316126af602eJens Axboe * use msec to avoid dropping too much precision when 7925fb8d7912ebf6fabb9ad3a61c4cd316126af602eJens Axboe * storing as an integer. 7935fb8d7912ebf6fabb9ad3a61c4cd316126af602eJens Axboe */ 794b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe minx = minx * 1000.0; 795b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe maxx = maxx * 1000.0; 796b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe 7973ca30e63c16734837336380b6f40b85e97579167Jens Axboe INIT_PRIO_TREE_NODE(&x->node); 798b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.start = minx; 799b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.last = maxx; 800cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe x->tooltip = strdup(tooltip); 801b552682725e8269e4977d3a11317ec27c1720ea2Jens Axboe if (x->node.last == x->node.start) { 802b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.last += fabs(g->xtick_delta); 803b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (x->node.last == x->node.start) 804b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x->node.last++; 805b552682725e8269e4977d3a11317ec27c1720ea2Jens Axboe } 806b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 8074c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe /* 8084c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe * If ret != &x->node, we have an alias. Since the values 8094c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe * should be identical, we can drop it 8104c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe */ 8114c0cd537f392e8a824d0080675f07b84c355af20Jens Axboe ret = prio_tree_insert(&i->prio_tree, &x->node); 812cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (ret != &x->node) { 813cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_value *alias; 814cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 815cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe alias = container_of(ret, struct graph_value, node); 816cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_add_tail(&x->alias, &alias->alias); 817bd10a0694df75c5ae0257ac2f6c8b51061859321Jens Axboe } else 818cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe x->flags = GV_F_ON_PRIO; 8198dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe } else 8208dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe x->flags = GV_F_PRIO_SKIP; 821af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 822b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (g->per_label_limit != -1 && 823b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe i->value_count > g->per_label_limit) { 824c148daed3da130062a7575d5667ca0e044927153Jens Axboe int to_drop = 1; 825c148daed3da130062a7575d5667ca0e044927153Jens Axboe 826c148daed3da130062a7575d5667ca0e044927153Jens Axboe /* 827c148daed3da130062a7575d5667ca0e044927153Jens Axboe * If the limit was dynamically reduced, making us more 828c148daed3da130062a7575d5667ca0e044927153Jens Axboe * than 1 entry ahead after adding this one, drop two 829c148daed3da130062a7575d5667ca0e044927153Jens Axboe * entries. This will make us (eventually) reach the 830c148daed3da130062a7575d5667ca0e044927153Jens Axboe * specified limit. 831c148daed3da130062a7575d5667ca0e044927153Jens Axboe */ 832b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe if (i->value_count - g->per_label_limit >= 2) 833c148daed3da130062a7575d5667ca0e044927153Jens Axboe to_drop = 2; 834c148daed3da130062a7575d5667ca0e044927153Jens Axboe 835cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe while (to_drop-- && !flist_empty(&i->value_list)) { 836cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe x = flist_entry(i->value_list.next, struct graph_value, list); 837cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe graph_value_drop(i, x); 838cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 839cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe /* 840cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe * If we have aliases, we could drop > 1 above. 841cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe */ 842cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (i->value_count <= g->per_label_limit) 843cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe break; 844c148daed3da130062a7575d5667ca0e044927153Jens Axboe } 845af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 846af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 847af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 8488dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboeint graph_add_data(struct graph *bg, graph_label_t label, const double value) 849af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 8508dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe struct graph_label *i = label; 851af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double *d; 852af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 853af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron d = malloc(sizeof(*d)); 854af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron *d = value; 855af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 856b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe graph_label_add_value(i, d, NULL); 857af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return 0; 858af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 859af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 86001a947f067b1a03add33e645ece73ac19d8257ddJens Axboestatic int graph_nonzero_y(struct graph_label *l) 86101a947f067b1a03add33e645ece73ac19d8257ddJens Axboe{ 86201a947f067b1a03add33e645ece73ac19d8257ddJens Axboe struct flist_head *entry; 86301a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 86401a947f067b1a03add33e645ece73ac19d8257ddJens Axboe flist_for_each(entry, &l->value_list) { 86501a947f067b1a03add33e645ece73ac19d8257ddJens Axboe struct graph_value *v; 86601a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 86701a947f067b1a03add33e645ece73ac19d8257ddJens Axboe v = flist_entry(entry, struct graph_value, list); 86801a947f067b1a03add33e645ece73ac19d8257ddJens Axboe if (gety(v) != 0.0) 86901a947f067b1a03add33e645ece73ac19d8257ddJens Axboe return 1; 87001a947f067b1a03add33e645ece73ac19d8257ddJens Axboe } 87101a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 87201a947f067b1a03add33e645ece73ac19d8257ddJens Axboe return 0; 87301a947f067b1a03add33e645ece73ac19d8257ddJens Axboe} 87401a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 8758dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboeint graph_add_xy_data(struct graph *bg, graph_label_t label, 87693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe const double x, const double y, const char *tooltip) 877af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 8788dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe struct graph_label *i = label; 879af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron struct xyvalue *xy; 880af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 88101a947f067b1a03add33e645ece73ac19d8257ddJens Axboe if (bg->dont_graph_all_zeroes && y == 0.0 && !graph_nonzero_y(i)) 88201a947f067b1a03add33e645ece73ac19d8257ddJens Axboe i->hide = 1; 88301a947f067b1a03add33e645ece73ac19d8257ddJens Axboe else 88401a947f067b1a03add33e645ece73ac19d8257ddJens Axboe i->hide = 0; 88501a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 88601a947f067b1a03add33e645ece73ac19d8257ddJens Axboe xy = malloc(sizeof(*xy)); 88701a947f067b1a03add33e645ece73ac19d8257ddJens Axboe xy->x = x; 88801a947f067b1a03add33e645ece73ac19d8257ddJens Axboe xy->y = y; 88901a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 890b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe graph_label_add_value(i, xy, tooltip); 891af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron return 0; 892af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 893af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 894cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic void graph_free_values(struct graph_label *l) 895af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 896cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_value *i; 897af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 898cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe while (!flist_empty(&l->value_list)) { 899cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(l->value_list.next, struct graph_value, list); 900cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe graph_value_drop(l, i); 901af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 902af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 903af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 904cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboestatic void graph_free_labels(struct graph *g) 905af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 906cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_label *i; 907af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 908cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe while (!flist_empty(&g->label_list)) { 909cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(g->label_list.next, struct graph_label, list); 910cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_del(&i->list); 911cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe graph_free_values(i); 912b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(i); 913af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron } 914af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 915af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 9168dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboevoid graph_set_color(struct graph *gr, graph_label_t label, double red, 9178dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe double green, double blue) 918af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 9198dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe struct graph_label *i = label; 920af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron double r, g, b; 921af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 922cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (red < 0.0) { /* invisible color */ 923cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron r = -1.0; 924cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron g = -1.0; 925cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron b = -1.0; 926cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron } else { 927cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron r = fabs(red); 928cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron g = fabs(green); 929cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron b = fabs(blue); 930cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron 931cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (r > 1.0) 932cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron r = 1.0; 933cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (g > 1.0) 934cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron g = 1.0; 935cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron if (b > 1.0) 936b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe b = 1.0; 937cae0872709f690086f896f7327e136c7db7ba567Stephen M. Cameron } 938af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 9398dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe i->r = r; 9408dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe i->g = g; 9418dfd6071e1a4fd3966c0a77dbb7d719c52433b54Jens Axboe i->b = b; 942af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 943af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 944af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid graph_free(struct graph *bg) 945af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 946b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(bg->title); 947b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(bg->xtitle); 948b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe free(bg->ytitle); 949cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe graph_free_labels(bg); 950af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 951af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 952af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron/* For each line in the line graph, up to per_label_limit segments may 953af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * be added. After that, adding more data to the end of the line 954af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron * causes data to drop off of the front of the line. 955af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron */ 956af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameronvoid line_graph_set_data_count_limit(struct graph *g, int per_label_limit) 957af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron{ 958af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron g->per_label_limit = per_label_limit; 959af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron} 960af58ef32b7398d791168af54aa4aab0b23192f90Stephen M. Cameron 961def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameronvoid graph_add_extra_space(struct graph *g, double left_percent, double right_percent, 962def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron double top_percent, double bottom_percent) 963def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron{ 964def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->left_extra = left_percent; 965def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->right_extra = right_percent; 966def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->top_extra = top_percent; 967def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron g->bottom_extra = bottom_percent; 968def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron} 969def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 970d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe/* 971d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * Normally values are logged in a base unit of 0, but for other purposes 972d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * it makes more sense to log in higher unit. For instance for bandwidth 973d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe * purposes, you may want to log in KB/sec (or MB/sec) rather than bytes/sec. 974d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe */ 975d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboevoid graph_set_base_offset(struct graph *g, unsigned int base_offset) 976d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe{ 977d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe g->base_offset = base_offset; 978d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe} 979d8fbeefb67641e9f63088b329de78a26a69fdbaeJens Axboe 98093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboeint graph_has_tooltips(struct graph *g) 98193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe{ 982cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 98393e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe struct graph_label *i; 98493e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 985cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &g->label_list) { 986cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_label, list); 987cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 988cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (!prio_tree_empty(&i->prio_tree)) 98993e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return 1; 990cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 99193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 99293e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return 0; 99393e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe} 99493e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 99593e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboeint graph_contains_xy(struct graph *g, int x, int y) 99693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe{ 99793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int first_x = g->xoffset; 99893e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int last_x = g->xoffset + g->xdim; 99993e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int first_y = g->yoffset; 100093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe int last_y = g->yoffset + g->ydim; 100193e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 100293e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return (x >= first_x && x <= last_x) && (y >= first_y && y <= last_y); 100393e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe} 1004def0ac29a7eb92282cf7f208b229261bb254ca00Stephen M. Cameron 1005b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboeconst char *graph_find_tooltip(struct graph *g, int ix, int iy) 100693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe{ 1007b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double x = ix, y = iy; 1008b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_iter iter; 1009b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct prio_tree_node *n; 1010b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe struct graph_value *best = NULL; 1011cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct flist_head *entry; 1012b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe double best_delta; 1013b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double maxy, miny; 101493e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 1015b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe x -= g->xoffset; 1016b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe y -= g->yoffset; 101793e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 1018b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe x = g->xtick_zero_val + ((x - g->xtick_zero) * g->xtick_delta); 1019b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe y = g->ytick_zero_val + ((y - g->ytick_zero) * g->ytick_delta); 102093e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 1021b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe x = x * 1000.0; 1022b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe maxy = y + (g->ytick_one_val * TOOLTIP_DELTA); 1023b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe miny = y - (g->ytick_one_val * TOOLTIP_DELTA); 1024b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe best_delta = UINT_MAX; 1025cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe flist_for_each(entry, &g->label_list) { 1026cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_label *i; 1027cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 1028cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe i = flist_entry(entry, struct graph_label, list); 102901a947f067b1a03add33e645ece73ac19d8257ddJens Axboe if (i->hide) 103001a947f067b1a03add33e645ece73ac19d8257ddJens Axboe continue; 1031cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 103208d7d5a80f3698f9a5b362831762c23e99fd9a22Jens Axboe INIT_PRIO_TREE_ITER(&iter); 1033b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe prio_tree_iter_init(&iter, &i->prio_tree, x, x); 1034b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 1035b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe n = prio_tree_next(&iter); 1036b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (!n) 1037b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe continue; 1038b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 1039b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe do { 1040cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe struct graph_value *v, *rootv; 1041b7a69ad89e65cb4f38ccf164ae7c00bb4efe0ef5Jens Axboe double yval, ydiff; 1042b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 1043b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe v = container_of(n, struct graph_value, node); 1044cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe rootv = v; 1045cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe do { 1046cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe yval = gety(v); 1047cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe ydiff = fabs(yval - y); 1048cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe 1049cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe /* 1050cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe * zero delta, or within or match critera, break 1051cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe */ 1052cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (ydiff < best_delta) { 1053cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe best_delta = ydiff; 1054cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (!best_delta || 1055cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe (yval >= miny && yval <= maxy)) { 1056cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe best = v; 1057cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe break; 1058cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 1059b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } 1060cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe if (!flist_empty(&v->alias)) 1061cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe v = flist_entry(v->alias.next, struct graph_value, alias); 1062cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } while (v != rootv); 1063b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe } while ((n = prio_tree_next(&iter)) != NULL); 1064b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 1065b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe /* 1066b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe * If we got matches in one label, don't check others. 1067b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe */ 1068d0db819d9c5abe904f85a3b21a95023fef007f20Jens Axboe if (best) 1069d0db819d9c5abe904f85a3b21a95023fef007f20Jens Axboe break; 1070cdae5ff83147bedec73318e347e39d4c388da2b9Jens Axboe } 1071b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe 1072b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe if (best) 1073b65c7ec44355b9bc4d6c5ee6613dfb895dace3d6Jens Axboe return best->tooltip; 107493e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe 107593e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe return NULL; 107693e2db2bdbedbd6954bb0e0632514cae659fc30eJens Axboe} 107701a947f067b1a03add33e645ece73ac19d8257ddJens Axboe 107801a947f067b1a03add33e645ece73ac19d8257ddJens Axboevoid graph_set_graph_all_zeroes(struct graph *g, unsigned int set) 107901a947f067b1a03add33e645ece73ac19d8257ddJens Axboe{ 108001a947f067b1a03add33e645ece73ac19d8257ddJens Axboe g->dont_graph_all_zeroes = !set; 108101a947f067b1a03add33e645ece73ac19d8257ddJens Axboe} 1082