From: Carl Worth Date: Sun, 10 Nov 2013 02:48:11 +0000 (-0800) Subject: Expand to add CPU/GPU load and frame latency graphs. X-Git-Url: https://git.cworth.org/git?p=acre;a=commitdiff_plain;h=refs%2Fheads%2Facre-fips Expand to add CPU/GPU load and frame latency graphs. The load graph shows both CPU and GPU load as separate lines. The loads are also used to choose which colors for the frame-time bars, (whether CPU-bound or GPU-bound). --- diff --git a/acre-x.c b/acre-x.c index e62c596..22cb063 100644 --- a/acre-x.c +++ b/acre-x.c @@ -31,15 +31,41 @@ #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_fips_data (const char *filename) +_create_chart (const char *title, + const char *x_axis_label, + const char *y_axis_label) { - FILE *file; acre_t *acre; - acre_data_t *frame_time; + + acre = acre_create (); + + acre_set_title (acre, title); + acre_set_x_axis_label (acre, x_axis_label); + acre_set_y_axis_label (acre, y_axis_label); + + return acre; +} + +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; @@ -48,17 +74,28 @@ load_fips_data (const char *filename) if (file == NULL) { fprintf (stderr, "Failed to open %s: %s\n", filename, strerror (errno)); - return NULL; + return 1; } - acre = acre_create (); + 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"); - acre_set_title (acre, filename); - acre_set_x_axis_label (acre, "Frame #"); - acre_set_y_axis_label (acre, "Frame time (ms)"); + gpu_load_data = acre_data_create (); + acre_data_set_name (gpu_load_data, "GPU"); - frame_time = acre_data_create (); - acre_data_set_style (frame_time, ACRE_STYLE_BARS_OR_LINE); + 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; @@ -69,35 +106,80 @@ load_fips_data (const char *filename) s = line; - if (STRNCMP_LITERAL (s, "frame-time: ") == 0) { + if (STRNCMP_LITERAL (s, "frame: ") == 0) { unsigned frame; - int64_t frame_time_ns; - - s += strlen("frame-time: "); - - scanned = sscanf (s, "%d %" SCNu64, - &frame, &frame_time_ns); - if (scanned != 2) { + 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 (frame_time, frame, - frame_time_ns / 1e6); + 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 { - /* Ignoring all other lines. */ + /* Ignore all other lines. */ } } free (line); - acre_add_data (acre, frame_time); + 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; @@ -107,12 +189,7 @@ 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); - - acre_set_x_axis_range (acre, x_min, x_max); - acre_draw (acre, cr, width, height); + draw_cairo (cr, charts, width, height, x_min, x_max); cairo_destroy (cr); @@ -120,27 +197,47 @@ draw (Display *dpy, Window window, Visual *visual, acre_t *acre, } static void -draw_svg (acre_t *acre, int width, int height, double x_min, double x_max) +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 ("acre-fips.svg", width, height); + surface = cairo_svg_surface_create (filename, width, height); cr = cairo_create (surface); - acre_set_x_axis_range (acre, x_min, x_max); - acre_draw (acre, cr, width, height); + 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")); @@ -151,17 +248,18 @@ handle_events(Display *dpy, Window window, Visual *visual, 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 @@ -202,12 +300,20 @@ handle_events(Display *dpy, Window window, Visual *visual, } 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, width, height, x_min, x_max); + 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 { @@ -232,11 +338,12 @@ 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; @@ -247,10 +354,9 @@ main (int argc, char *argv[]) exit (1); } - acre = load_fips_data (argv[1]); - - if (acre == NULL) - return 1; + err = load_fips_charts (&charts, argv[1]); + if (err) + return err; dpy = XOpenDisplay (NULL); @@ -279,9 +385,11 @@ main (int argc, char *argv[]) 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);