1 /* acre - A cairo-based library for creating plots and charts.
3 * Copyright © 2009 Carl Worth <cworth@cworth.org>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
28 #include <cairo-svg.h>
29 #include <cairo-xlib.h>
38 acre_t *frame_latency;
41 #define STRNCMP_LITERAL(var, literal) \
42 strncmp ((var), (literal), sizeof (literal) - 1)
45 _create_chart (const char *title,
46 const char *x_axis_label,
47 const char *y_axis_label)
51 acre = acre_create ();
53 acre_set_title (acre, title);
54 acre_set_x_axis_label (acre, x_axis_label);
55 acre_set_y_axis_label (acre, y_axis_label);
61 load_fips_charts (charts_t *charts, const char *filename)
64 acre_data_t *cpu_load_data;
65 acre_data_t *gpu_load_data;
66 acre_data_t *cpu_bound_frame_time_data;
67 acre_data_t *gpu_bound_frame_time_data;
68 acre_data_t *frame_latency_data;
69 char *line = NULL, *s;
73 file = fopen (filename, "r");
75 fprintf (stderr, "Failed to open %s: %s\n",
76 filename, strerror (errno));
80 charts->cpu_gpu_load = _create_chart ("CPU/GPU load", "Frame #", "Load");
81 charts->frame_time = _create_chart ("Frame time", "Frame #", "Time (ms)");
82 charts->frame_latency = _create_chart ("Frame latency", "Frame #", "Latency (ms)");
84 cpu_load_data = acre_data_create ();
85 acre_data_set_name (cpu_load_data, "CPU");
87 gpu_load_data = acre_data_create ();
88 acre_data_set_name (gpu_load_data, "GPU");
90 cpu_bound_frame_time_data = acre_data_create ();
91 acre_data_set_style (cpu_bound_frame_time_data, ACRE_STYLE_BARS);
92 acre_data_set_name (cpu_bound_frame_time_data, "CPU Bound");
94 gpu_bound_frame_time_data = acre_data_create ();
95 acre_data_set_style (gpu_bound_frame_time_data, ACRE_STYLE_BARS);
96 acre_data_set_name (gpu_bound_frame_time_data, "GPU Bound");
98 frame_latency_data = acre_data_create ();
103 bytes = getline (&line, &line_size, file);
109 if (STRNCMP_LITERAL (s, "frame: ") == 0) {
111 double frame_time_ms, frame_latency_ms;
112 double cpu_load, gpu_load;
114 s += strlen("frame: ");
116 scanned = sscanf (s, "%d %lg %lg %lg %lg",
123 fprintf (stderr, "Warning: Failed to parse line: %s\n", line);
127 acre_data_add_point_2d (cpu_load_data, frame, cpu_load);
128 acre_data_add_point_2d (gpu_load_data, frame, gpu_load);
129 if (cpu_load > gpu_load) {
130 acre_data_add_point_2d (
131 cpu_bound_frame_time_data,
132 frame, frame_time_ms);
134 acre_data_add_point_2d (
135 gpu_bound_frame_time_data,
136 frame, frame_time_ms);
138 acre_data_add_point_2d (frame_latency_data, frame,
142 /* Ignore all other lines. */
148 acre_add_data (charts->cpu_gpu_load, cpu_load_data);
149 acre_add_data (charts->cpu_gpu_load, gpu_load_data);
150 acre_add_data (charts->frame_time, cpu_bound_frame_time_data);
151 acre_add_data (charts->frame_time, gpu_bound_frame_time_data);
152 acre_add_data (charts->frame_latency, frame_latency_data);
158 draw_cairo (cairo_t *cr, charts_t *charts, int width, int height,
159 double x_min, double x_max)
161 int chart_height = height / 3;
164 cairo_set_source_rgb (cr, 1, 1, 1);
167 acre_set_x_axis_range (charts->cpu_gpu_load, x_min, x_max);
168 acre_draw (charts->cpu_gpu_load, cr, width, chart_height);
170 cairo_translate (cr, 0.0, chart_height);
172 acre_set_x_axis_range (charts->frame_time, x_min, x_max);
173 acre_draw (charts->frame_time, cr, width, chart_height);
175 cairo_translate (cr, 0.0, chart_height);
177 acre_set_x_axis_range (charts->frame_latency, x_min, x_max);
178 acre_draw (charts->frame_latency, cr, width, chart_height);
182 draw_xlib (Display *dpy, Window window, Visual *visual, charts_t *charts,
183 int width, int height, double x_min, double x_max)
186 cairo_surface_t *surface;
188 surface = cairo_xlib_surface_create (dpy, window, visual,
190 cr = cairo_create (surface);
192 draw_cairo (cr, charts, width, height, x_min, x_max);
196 cairo_surface_destroy (surface);
200 draw_svg (const char *filename, charts_t *charts,
201 int width, int height, double x_min, double x_max)
204 cairo_surface_t *surface;
206 surface = cairo_svg_surface_create (filename, width, height);
208 cr = cairo_create (surface);
210 draw_cairo (cr, charts, width, height, x_min, x_max);
214 cairo_surface_destroy (surface);
218 draw_png (const char *filename, charts_t *charts,
219 int width, int height, double x_min, double x_max)
222 cairo_surface_t *surface;
224 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
227 cr = cairo_create (surface);
229 draw_cairo (cr, charts, width, height, x_min, x_max);
233 cairo_surface_write_to_png (surface, filename);
235 cairo_surface_destroy (surface);
239 handle_events(Display *dpy, Window window, Visual *visual,
240 charts_t *charts, int width, int height)
243 KeyCode quit_code = XKeysymToKeycode (dpy, XStringToKeysym("Q"));
244 KeyCode escape_code = XKeysymToKeycode (dpy, XStringToKeysym("Escape"));
245 KeyCode left_code = XKeysymToKeycode (dpy, XStringToKeysym("Left"));
246 KeyCode right_code = XKeysymToKeycode (dpy, XStringToKeysym("Right"));
247 KeyCode plus_code = XKeysymToKeycode (dpy, XStringToKeysym("plus"));
248 KeyCode equal_code = XKeysymToKeycode (dpy, XStringToKeysym("equal"));
249 KeyCode minus_code = XKeysymToKeycode (dpy, XStringToKeysym("minus"));
250 KeyCode home_code = XKeysymToKeycode (dpy, XStringToKeysym("Home"));
251 KeyCode png_code = XKeysymToKeycode (dpy, XStringToKeysym("P"));
252 KeyCode svg_code = XKeysymToKeycode (dpy, XStringToKeysym("S"));
254 bool need_redraw = false;
255 double x_min, x_max, shift;
257 acre_get_x_axis_data_range (charts->cpu_gpu_load, &x_min, &x_max);
260 if (! XPending (dpy) && need_redraw)
261 draw_xlib (dpy, window, visual, charts,
262 width, height, x_min, x_max);
266 XNextEvent (dpy, &xev);
270 keycode = xev.xkey.keycode;
271 if (keycode == quit_code ||
272 keycode == escape_code)
276 else if (keycode == left_code)
278 shift = PAN * (x_max - x_min);
282 else if (keycode == right_code)
284 shift = PAN * (x_max - x_min);
288 else if (keycode == plus_code ||
289 keycode == equal_code)
291 shift = ZOOM * (x_max - x_min);
295 else if (keycode == minus_code)
297 shift = (ZOOM/(1 - 2 * ZOOM)) * (x_max - x_min);
301 else if (keycode == home_code)
303 acre_get_x_axis_data_range (charts->cpu_gpu_load,
306 else if (keycode == svg_code)
309 draw_svg ("acre-fips.svg", charts,
310 width, height, x_min, x_max);
312 else if (keycode == png_code)
315 draw_png ("acre-fips.png", charts,
316 width, height, x_min, x_max);
323 case ConfigureNotify:
324 width = xev.xconfigure.width;
325 height = xev.xconfigure.height;
328 if (xev.xexpose.count == 0)
336 main (int argc, char *argv[])
341 XSetWindowAttributes window_attr;
343 unsigned long window_mask, event_mask;
352 fprintf (stderr, "Usage: acre-x data-file\n");
353 fprintf (stderr, "Where the data file is the output from fips (with frame-timing feature.\n");
357 err = load_fips_charts (&charts, argv[1]);
361 dpy = XOpenDisplay (NULL);
364 fprintf(stderr, "Failed to open display %s\n",
369 root = DefaultRootWindow (dpy);
370 white = WhitePixel (dpy, DefaultScreen (dpy));
371 visual = DefaultVisual (dpy, DefaultScreen (dpy));
372 colormap = XCreateColormap (dpy, root, visual, AllocNone);
373 event_mask = KeyPressMask | StructureNotifyMask | ExposureMask;
376 window_mask |= CWBackPixel; window_attr.background_pixel = white;
377 window_mask |= CWBorderPixel; window_attr.border_pixel = white;
378 window_mask |= CWColormap; window_attr.colormap = colormap;
379 window_mask |= CWEventMask; window_attr.event_mask = event_mask;
381 window = XCreateWindow(dpy, root, 0, 0, width, height, 0,
382 DefaultDepth (dpy, DefaultScreen (dpy)),
384 window_mask, &window_attr);
386 XMapWindow (dpy, window);
388 handle_events (dpy, window, visual, &charts, width, height);
390 acre_destroy (charts.cpu_gpu_load);
391 acre_destroy (charts.frame_time);
392 acre_destroy (charts.frame_latency);
394 XDestroyWindow (dpy, window);