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