X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=acre-x.c;h=22cb063d01a49f8ee79fd8d9bccc7e2cd6012858;hb=refs%2Fheads%2Facre-fips;hp=e89c7fcf285f556d1b402a245cd3f43f42f57f1a;hpb=12b6b0f6a439c7838daac5e2a1e5764bd0218936;p=acre diff --git a/acre-x.c b/acre-x.c index e89c7fc..22cb063 100644 --- a/acre-x.c +++ b/acre-x.c @@ -17,64 +17,169 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include #include +#include +#include +#include #include + +#include #include #include "acre.h" #include "math.h" +typedef struct +{ + acre_t *cpu_gpu_load; + acre_t *frame_time; + acre_t *frame_latency; +} charts_t; + +#define STRNCMP_LITERAL(var, literal) \ + strncmp ((var), (literal), sizeof (literal) - 1) + static acre_t * -load_chart (void) +_create_chart (const char *title, + const char *x_axis_label, + const char *y_axis_label) { acre_t *acre; - acre_data_t *data0, *data1, *data2; - int i; acre = acre_create (); - acre_set_x_axis_label (acre, "X axis"); - acre_set_y_axis_label (acre, "Y axis"); - data0 = acre_data_create (); - data1 = acre_data_create (); - data2 = acre_data_create (); + acre_set_title (acre, title); + acre_set_x_axis_label (acre, x_axis_label); + acre_set_y_axis_label (acre, y_axis_label); - acre_data_set_name (data0, "Data 0"); - acre_data_set_name (data1, "Data 1"); - acre_data_set_name (data2, "Data 2"); + return acre; +} - for (i = 0; i <= 100; i++) { - acre_data_add_point_2d (data0, i, 0 - (i/3.0)*(i/3.0)); +static int +load_fips_charts (charts_t *charts, const char *filename) +{ + FILE *file; + acre_data_t *cpu_load_data; + acre_data_t *gpu_load_data; + acre_data_t *cpu_bound_frame_time_data; + acre_data_t *gpu_bound_frame_time_data; + acre_data_t *frame_latency_data; + char *line = NULL, *s; + size_t line_size; + ssize_t bytes; + + file = fopen (filename, "r"); + if (file == NULL) { + fprintf (stderr, "Failed to open %s: %s\n", + filename, strerror (errno)); + return 1; } - for (i = 0; i < 100; i++) { - double t = 1.0 - (i / 100.0); - acre_data_add_point_2d (data1, i, -1000 * (1.0 - t*t*t)); - } - - for (i = 0; i <= 1000; i++) { - double t, x, y; - t = i/10.0 - 50; - x = t + 50; - if (t == 0.0) - y = -200; - else - y = -1200 + 1000 * sin(t) / t; - acre_data_add_point_2d (data2, x, y); + charts->cpu_gpu_load = _create_chart ("CPU/GPU load", "Frame #", "Load"); + charts->frame_time = _create_chart ("Frame time", "Frame #", "Time (ms)"); + charts->frame_latency = _create_chart ("Frame latency", "Frame #", "Latency (ms)"); + + cpu_load_data = acre_data_create (); + acre_data_set_name (cpu_load_data, "CPU"); + + gpu_load_data = acre_data_create (); + acre_data_set_name (gpu_load_data, "GPU"); + + cpu_bound_frame_time_data = acre_data_create (); + acre_data_set_style (cpu_bound_frame_time_data, ACRE_STYLE_BARS); + acre_data_set_name (cpu_bound_frame_time_data, "CPU Bound"); + + gpu_bound_frame_time_data = acre_data_create (); + acre_data_set_style (gpu_bound_frame_time_data, ACRE_STYLE_BARS); + acre_data_set_name (gpu_bound_frame_time_data, "GPU Bound"); + + frame_latency_data = acre_data_create (); + + while (1) { + int scanned; + + bytes = getline (&line, &line_size, file); + if (bytes == -1) + break; + + s = line; + + if (STRNCMP_LITERAL (s, "frame: ") == 0) { + unsigned frame; + double frame_time_ms, frame_latency_ms; + double cpu_load, gpu_load; + + s += strlen("frame: "); + + scanned = sscanf (s, "%d %lg %lg %lg %lg", + &frame, + &frame_time_ms, + &frame_latency_ms, + &cpu_load, + &gpu_load); + if (scanned != 5) { + fprintf (stderr, "Warning: Failed to parse line: %s\n", line); + continue; + } + + acre_data_add_point_2d (cpu_load_data, frame, cpu_load); + acre_data_add_point_2d (gpu_load_data, frame, gpu_load); + if (cpu_load > gpu_load) { + acre_data_add_point_2d ( + cpu_bound_frame_time_data, + frame, frame_time_ms); + } else { + acre_data_add_point_2d ( + gpu_bound_frame_time_data, + frame, frame_time_ms); + } + acre_data_add_point_2d (frame_latency_data, frame, + frame_latency_ms); + + } else { + /* Ignore all other lines. */ + } } - acre_add_data (acre, data0); - acre_add_data (acre, data1); - acre_add_data (acre, data2); + free (line); - acre_set_title (acre, "All the data"); + acre_add_data (charts->cpu_gpu_load, cpu_load_data); + acre_add_data (charts->cpu_gpu_load, gpu_load_data); + acre_add_data (charts->frame_time, cpu_bound_frame_time_data); + acre_add_data (charts->frame_time, gpu_bound_frame_time_data); + acre_add_data (charts->frame_latency, frame_latency_data); - return acre; + return 0; } static void -draw (Display *dpy, Window window, Visual *visual, acre_t *acre, +draw_cairo (cairo_t *cr, charts_t *charts, int width, int height, + double x_min, double x_max) +{ + int chart_height = height / 3; + + /* Erase to white */ + cairo_set_source_rgb (cr, 1, 1, 1); + cairo_paint (cr); + + acre_set_x_axis_range (charts->cpu_gpu_load, x_min, x_max); + acre_draw (charts->cpu_gpu_load, cr, width, chart_height); + + cairo_translate (cr, 0.0, chart_height); + + acre_set_x_axis_range (charts->frame_time, x_min, x_max); + acre_draw (charts->frame_time, cr, width, chart_height); + + cairo_translate (cr, 0.0, chart_height); + + acre_set_x_axis_range (charts->frame_latency, x_min, x_max); + acre_draw (charts->frame_latency, cr, width, chart_height); +} + +static void +draw_xlib (Display *dpy, Window window, Visual *visual, charts_t *charts, int width, int height, double x_min, double x_max) { cairo_t *cr; @@ -84,49 +189,87 @@ draw (Display *dpy, Window window, Visual *visual, acre_t *acre, width, height); cr = cairo_create (surface); - /* Erase to white */ - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_paint (cr); + draw_cairo (cr, charts, width, height, x_min, x_max); - acre_set_x_axis_range (acre, x_min, x_max); - acre_draw (acre, cr, width, height); + cairo_destroy (cr); + + cairo_surface_destroy (surface); +} + +static void +draw_svg (const char *filename, charts_t *charts, + int width, int height, double x_min, double x_max) +{ + cairo_t *cr; + cairo_surface_t *surface; + + surface = cairo_svg_surface_create (filename, width, height); + + cr = cairo_create (surface); + + draw_cairo (cr, charts, width, height, x_min, x_max); cairo_destroy (cr); cairo_surface_destroy (surface); } +static void +draw_png (const char *filename, charts_t *charts, + int width, int height, double x_min, double x_max) +{ + cairo_t *cr; + cairo_surface_t *surface; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + + cr = cairo_create (surface); + + draw_cairo (cr, charts, width, height, x_min, x_max); + + cairo_destroy (cr); + + cairo_surface_write_to_png (surface, filename); + + cairo_surface_destroy (surface); +} static void handle_events(Display *dpy, Window window, Visual *visual, - acre_t *acre, int width, int height) + charts_t *charts, int width, int height) { XEvent xev; KeyCode quit_code = XKeysymToKeycode (dpy, XStringToKeysym("Q")); + KeyCode escape_code = XKeysymToKeycode (dpy, XStringToKeysym("Escape")); KeyCode left_code = XKeysymToKeycode (dpy, XStringToKeysym("Left")); KeyCode right_code = XKeysymToKeycode (dpy, XStringToKeysym("Right")); KeyCode plus_code = XKeysymToKeycode (dpy, XStringToKeysym("plus")); KeyCode equal_code = XKeysymToKeycode (dpy, XStringToKeysym("equal")); KeyCode minus_code = XKeysymToKeycode (dpy, XStringToKeysym("minus")); KeyCode home_code = XKeysymToKeycode (dpy, XStringToKeysym("Home")); + KeyCode png_code = XKeysymToKeycode (dpy, XStringToKeysym("P")); + KeyCode svg_code = XKeysymToKeycode (dpy, XStringToKeysym("S")); KeyCode keycode; bool need_redraw = false; double x_min, x_max, shift; - acre_get_x_axis_data_range (acre, &x_min, &x_max); + acre_get_x_axis_data_range (charts->cpu_gpu_load, &x_min, &x_max); while (1) { if (! XPending (dpy) && need_redraw) - draw (dpy, window, visual, acre, - width, height, x_min, x_max); + draw_xlib (dpy, window, visual, charts, + width, height, x_min, x_max); #define PAN 0.05 #define ZOOM PAN XNextEvent (dpy, &xev); switch (xev.type) { case KeyPress: + need_redraw = true; keycode = xev.xkey.keycode; - if (keycode == quit_code) + if (keycode == quit_code || + keycode == escape_code) { return; } @@ -151,15 +294,31 @@ handle_events(Display *dpy, Window window, Visual *visual, } else if (keycode == minus_code) { - shift = (1- 2*ZOOM) * (x_max - x_min); + shift = (ZOOM/(1 - 2 * ZOOM)) * (x_max - x_min); x_min -= shift; x_max += shift; } else if (keycode == home_code) { - acre_get_x_axis_data_range (acre, &x_min, &x_max); + acre_get_x_axis_data_range (charts->cpu_gpu_load, + &x_min, &x_max); + } + else if (keycode == svg_code) + { + need_redraw = false; + draw_svg ("acre-fips.svg", charts, + width, height, x_min, x_max); + } + else if (keycode == png_code) + { + need_redraw = false; + draw_png ("acre-fips.png", charts, + width, height, x_min, x_max); + } + else + { + need_redraw = false; } - need_redraw = 1; break; case ConfigureNotify: width = xev.xconfigure.width; @@ -174,21 +333,30 @@ handle_events(Display *dpy, Window window, Visual *visual, } int -main (void) +main (int argc, char *argv[]) { Display *dpy; Window window, root; Visual *visual; - acre_t *acre; XSetWindowAttributes window_attr; Colormap colormap; unsigned long window_mask, event_mask; unsigned long white; + charts_t charts; + int err; int width = 800; int height = 600; - acre = load_chart (); + if (argc < 2) { + fprintf (stderr, "Usage: acre-x data-file\n"); + fprintf (stderr, "Where the data file is the output from fips (with frame-timing feature.\n"); + exit (1); + } + + err = load_fips_charts (&charts, argv[1]); + if (err) + return err; dpy = XOpenDisplay (NULL); @@ -217,9 +385,11 @@ main (void) XMapWindow (dpy, window); - handle_events (dpy, window, visual, acre, width, height); + handle_events (dpy, window, visual, &charts, width, height); - acre_destroy (acre); + acre_destroy (charts.cpu_gpu_load); + acre_destroy (charts.frame_time); + acre_destroy (charts.frame_latency); XDestroyWindow (dpy, window); XCloseDisplay (dpy);