diff options
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/animated-resizing.c | 129 | ||||
-rw-r--r-- | tests/frame-stats.c | 182 | ||||
-rw-r--r-- | tests/frame-stats.h | 9 | ||||
-rw-r--r-- | tests/variable.c | 17 | ||||
-rw-r--r-- | tests/variable.h | 5 | ||||
-rw-r--r-- | tests/video-timer.c | 4 |
7 files changed, 218 insertions, 130 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am index dac59ae527..1dd397d7ff 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -263,6 +263,8 @@ testrevealer_DEPENDENCIES = $(TEST_DEPS) animated_resizing_SOURCES = \ animated-resizing.c \ + frame-stats.c \ + frame-stats.h \ variable.c \ variable.h diff --git a/tests/animated-resizing.c b/tests/animated-resizing.c index 8a34d9fc38..c37106dda3 100644 --- a/tests/animated-resizing.c +++ b/tests/animated-resizing.c @@ -4,7 +4,7 @@ #include <math.h> #include <string.h> -#include "variable.h" +#include "frame-stats.h" #define RADIUS 64 #define DIAMETER (2*RADIUS) @@ -19,11 +19,8 @@ static int window_width = WIDTH, window_height = HEIGHT; gint64 start_frame_time; static double angle; -static int max_stats = -1; -static double statistics_time = 5.; static double load_factor = 1.0; static double cb_no_resize = FALSE; -static gboolean machine_readable = FALSE; static cairo_surface_t *source_surface; @@ -114,114 +111,10 @@ on_window_draw (GtkWidget *widget, } static void -print_double (const char *description, - double value) -{ - if (machine_readable) - g_print ("%g\t", value); - else - g_print ("%s: %g\n", description, value); -} - -static void -print_variable (const char *description, - Variable *variable) -{ - if (variable->weight != 0) - { - if (machine_readable) - g_print ("%g\t%g\t", - variable_mean (variable), - variable_standard_deviation (variable)); - else - g_print ("%s: %g +/- %g\n", description, - variable_mean (variable), - variable_standard_deviation (variable)); - } - else - { - if (machine_readable) - g_print ("-\t-\t"); - else - g_print ("%s: <n/a>\n", description); - } -} - -static void -handle_frame_stats (GdkFrameClock *frame_clock) -{ - static int num_stats = 0; - static double last_print_time = 0; - static int frames_since_last_print = 0; - static gint64 frame_counter; - static gint64 last_handled_frame = -1; - - static Variable latency = VARIABLE_INIT; - - double current_time; - - current_time = g_get_monotonic_time (); - if (current_time >= last_print_time + 1000000 * statistics_time) - { - if (frames_since_last_print) - { - if (num_stats == 0 && machine_readable) - { - g_print ("# load_factor frame_rate latency\n"); - } - - num_stats++; - if (machine_readable) - g_print ("%g ", load_factor); - print_double ("Frame rate ", - frames_since_last_print / ((current_time - last_print_time) / 1000000.)); - - print_variable ("Latency", &latency); - - g_print ("\n"); - } - - last_print_time = current_time; - frames_since_last_print = 0; - variable_reset (&latency); - - if (num_stats == max_stats) - gtk_main_quit (); - } - - frames_since_last_print++; - - for (frame_counter = last_handled_frame; - frame_counter < gdk_frame_clock_get_frame_counter (frame_clock); - frame_counter++) - { - GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter); - GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (frame_clock, frame_counter - 1); - - if (!timings || gdk_frame_timings_get_complete (timings)) - last_handled_frame = frame_counter; - - if (timings && gdk_frame_timings_get_complete (timings) && previous_timings && - gdk_frame_timings_get_presentation_time (timings) != 0 && - gdk_frame_timings_get_presentation_time (previous_timings) != 0) - { - double display_time = (gdk_frame_timings_get_presentation_time (timings) - gdk_frame_timings_get_presentation_time (previous_timings)) / 1000.; - double frame_latency = (gdk_frame_timings_get_presentation_time (previous_timings) - gdk_frame_timings_get_frame_time (previous_timings)) / 1000. + display_time / 2; - - variable_add_weighted (&latency, frame_latency, display_time); - } - } -} - -static void on_frame (double progress) { - GdkFrameClock *frame_clock = gtk_widget_get_frame_clock (window); int jitter; - if (frame_clock) - handle_frame_stats (frame_clock); - angle = 2 * M_PI * progress; jitter = WINDOW_SIZE_JITTER * sin(angle); @@ -265,10 +158,7 @@ on_map_event (GtkWidget *widget, static GOptionEntry options[] = { { "factor", 'f', 0, G_OPTION_ARG_DOUBLE, &load_factor, "Load factor", "FACTOR" }, - { "max-statistics", 'm', 0, G_OPTION_ARG_INT, &max_stats, "Maximum statistics printed", NULL }, - { "machine-readable", 0, 0, G_OPTION_ARG_NONE, &machine_readable, "Print statistics in columns", NULL }, { "no-resize", 'n', 0, G_OPTION_ARG_NONE, &cb_no_resize, "No Resize", NULL }, - { "statistics-time", 's', 0, G_OPTION_ARG_DOUBLE, &statistics_time, "Statistics accumulation time", "TIME" }, { NULL } }; @@ -279,21 +169,26 @@ main(int argc, char **argv) GdkScreen *screen; GdkRectangle monitor_bounds; - if (!gtk_init_with_args (&argc, &argv, "", - options, NULL, &error)) + GOptionContext *context = g_option_context_new (NULL); + g_option_context_add_main_entries (context, options, NULL); + frame_stats_add_options (g_option_context_get_main_group (context)); + g_option_context_add_group (context, + gtk_get_option_group (TRUE)); + + if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("Option parsing failed: %s\n", error->message); return 1; } - g_print ("%sLoad factor: %g\n", - machine_readable ? "# " : "", + g_print ("# Load factor: %g\n", load_factor); - g_print ("%sResizing?: %s\n", - machine_readable ? "# " : "", + g_print ("# Resizing?: %s\n", cb_no_resize ? "no" : "yes"); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + frame_stats_ensure (GTK_WINDOW (window)); + gtk_window_set_keep_above (GTK_WINDOW (window), TRUE); gtk_window_set_gravity (GTK_WINDOW (window), GDK_GRAVITY_CENTER); gtk_widget_set_app_paintable (window, TRUE); diff --git a/tests/frame-stats.c b/tests/frame-stats.c new file mode 100644 index 0000000000..5d888d2856 --- /dev/null +++ b/tests/frame-stats.c @@ -0,0 +1,182 @@ +/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ + +#include <gtk/gtk.h> + +#include "frame-stats.h" +#include "variable.h" + +typedef struct FrameStats FrameStats; + +struct FrameStats +{ + GdkFrameClock *frame_clock; + + int num_stats; + double last_print_time; + int frames_since_last_print; + gint64 last_handled_frame; + + Variable latency; +}; + +static int max_stats = -1; +static double statistics_time = 5.; +static gboolean machine_readable = FALSE; + +static GOptionEntry frame_sync_options[] = { + { "max-statistics", 'm', 0, G_OPTION_ARG_INT, &max_stats, "Maximum statistics printed", NULL }, + { "machine-readable", 0, 0, G_OPTION_ARG_NONE, &machine_readable, "Print statistics in columns", NULL }, + { "statistics-time", 's', 0, G_OPTION_ARG_DOUBLE, &statistics_time, "Statistics accumulation time", "TIME" }, + { NULL } +}; + +void +frame_stats_add_options (GOptionGroup *group) +{ + g_option_group_add_entries (group, frame_sync_options); +} + +static void +print_double (const char *description, + double value) +{ + if (machine_readable) + g_print ("%g\t", value); + else + g_print ("%s: %g\n", description, value); +} + +static void +print_variable (const char *description, + Variable *variable) +{ + if (variable->weight != 0) + { + if (machine_readable) + g_print ("%g\t%g\t", + variable_mean (variable), + variable_standard_deviation (variable)); + else + g_print ("%s: %g +/- %g\n", description, + variable_mean (variable), + variable_standard_deviation (variable)); + } + else + { + if (machine_readable) + g_print ("-\t-\t"); + else + g_print ("%s: <n/a>\n", description); + } +} + +static void +on_frame_clock_after_paint (GdkFrameClock *frame_clock, + FrameStats *frame_stats) +{ + gint64 frame_counter; + gint64 current_time; + + current_time = g_get_monotonic_time (); + if (current_time >= frame_stats->last_print_time + 1000000 * statistics_time) + { + if (frame_stats->frames_since_last_print) + { + if (frame_stats->num_stats == 0 && machine_readable) + { + g_print ("# load_factor frame_rate latency\n"); + } + + frame_stats->num_stats++; + print_double ("Frame rate ", + frame_stats->frames_since_last_print / + ((current_time - frame_stats->last_print_time) / 1000000.)); + + print_variable ("Latency", &frame_stats->latency); + + g_print ("\n"); + } + + frame_stats->last_print_time = current_time; + frame_stats->frames_since_last_print = 0; + variable_init (&frame_stats->latency); + + if (frame_stats->num_stats == max_stats) + gtk_main_quit (); + } + + frame_stats->frames_since_last_print++; + + for (frame_counter = frame_stats->last_handled_frame; + frame_counter < gdk_frame_clock_get_frame_counter (frame_clock); + frame_counter++) + { + GdkFrameTimings *timings = gdk_frame_clock_get_timings (frame_clock, frame_counter); + GdkFrameTimings *previous_timings = gdk_frame_clock_get_timings (frame_clock, frame_counter - 1); + + if (!timings || gdk_frame_timings_get_complete (timings)) + frame_stats->last_handled_frame = frame_counter; + + if (timings && gdk_frame_timings_get_complete (timings) && previous_timings && + gdk_frame_timings_get_presentation_time (timings) != 0 && + gdk_frame_timings_get_presentation_time (previous_timings) != 0) + { + double display_time = (gdk_frame_timings_get_presentation_time (timings) - gdk_frame_timings_get_presentation_time (previous_timings)) / 1000.; + double frame_latency = (gdk_frame_timings_get_presentation_time (previous_timings) - gdk_frame_timings_get_frame_time (previous_timings)) / 1000. + display_time / 2; + + variable_add_weighted (&frame_stats->latency, frame_latency, display_time); + } + } +} + +void +on_window_realize (GtkWidget *window, + FrameStats *frame_stats) +{ + frame_stats->frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (window)); + g_signal_connect (frame_stats->frame_clock, "after-paint", + G_CALLBACK (on_frame_clock_after_paint), frame_stats); +} + +void +on_window_unrealize (GtkWidget *window, + FrameStats *frame_stats) +{ + g_signal_handlers_disconnect_by_func (frame_stats->frame_clock, + (gpointer) on_frame_clock_after_paint, + frame_stats); + frame_stats->frame_clock = NULL; +} + +void +on_window_destroy (GtkWidget *window, + FrameStats *stats) +{ + g_free (stats); +} + +void +frame_stats_ensure (GtkWindow *window) +{ + FrameStats *frame_stats; + + frame_stats = g_object_get_data (G_OBJECT (window), "frame-stats"); + if (frame_stats != NULL) + return; + + frame_stats = g_new0 (FrameStats, 1); + g_object_set_data (G_OBJECT (window), "frame-stats", frame_stats); + + variable_init (&frame_stats->latency); + frame_stats->last_handled_frame = -1; + + g_signal_connect (window, "realize", + G_CALLBACK (on_window_realize), frame_stats); + g_signal_connect (window, "unrealize", + G_CALLBACK (on_window_unrealize), frame_stats); + g_signal_connect (window, "destroy", + G_CALLBACK (on_window_destroy), frame_stats); + + if (gtk_widget_get_realized (GTK_WIDGET (window))) + on_window_realize (GTK_WIDGET (window), frame_stats); +} diff --git a/tests/frame-stats.h b/tests/frame-stats.h new file mode 100644 index 0000000000..9c046a7f97 --- /dev/null +++ b/tests/frame-stats.h @@ -0,0 +1,9 @@ +#ifndef __FRAME_STATS_H__ +#define __FRAME_STATS_H__ + +#include <gtk/gtk.h> + +void frame_stats_add_options (GOptionGroup *group); +void frame_stats_ensure (GtkWindow *window); + +#endif /* __FRAME_STATS_H__ */ diff --git a/tests/variable.c b/tests/variable.c index 9ce5d5d6ab..097d3a430e 100644 --- a/tests/variable.c +++ b/tests/variable.c @@ -4,6 +4,14 @@ #include "variable.h" void +variable_init (Variable *variable) +{ + variable->weight = 0.0; + variable->sum = 0.0; + variable->sum2 = 0.0; +} + +void variable_add_weighted (Variable *variable, double value, double weight) @@ -32,12 +40,3 @@ variable_standard_deviation (Variable *variable) double mean = variable_mean (variable); return sqrt (variable->sum2 / variable->weight - mean * mean); } - -void -variable_reset (Variable *variable) -{ - variable->weight = 0; - variable->sum = 0; - variable->sum2 = 0; -} - diff --git a/tests/variable.h b/tests/variable.h index d53dd58e97..72466897df 100644 --- a/tests/variable.h +++ b/tests/variable.h @@ -8,8 +8,9 @@ typedef struct double sum2; } Variable; -#define VARIABLE_INIT { 0, 0.0, 0.0 } +#define VARIABLE_INIT { 0.0, 0.0, 0.0 } +void variable_init (Variable *variable); void variable_add_weighted (Variable *variable, double value, double weight); @@ -19,5 +20,5 @@ double variable_mean (Variable *variable); double variable_standard_deviation (Variable *variable); void variable_reset (Variable *variable); -#endif /* __VARAIBLE_H__ */ +#endif /* __VARIABLE_H__ */ diff --git a/tests/video-timer.c b/tests/video-timer.c index f858240049..e665c6da7f 100644 --- a/tests/video-timer.c +++ b/tests/video-timer.c @@ -291,8 +291,8 @@ print_statistics (void) g_print ("playback rate adjustment: %g +/- %g %%\n", (variable_mean (&time_factor_stats) - 1) * 100, variable_standard_deviation (&time_factor_stats) * 100); - variable_reset (&latency_error); - variable_reset (&time_factor_stats); + variable_init (&latency_error); + variable_init (&time_factor_stats); dropped_frames = 0; n_frames = 0; last_print_time = now; |