[gtk] demo: Move benchmarking implementation to fishbowl widget



commit db5b8ca9970a94960f23fb25108f2cc73de9061b
Author: Benjamin Otte <otte redhat com>
Date:   Tue Apr 24 19:04:44 2018 +0200

    demo: Move benchmarking implementation to fishbowl widget

 demos/gtk-demo/fishbowl.c    | 163 -------------------------------
 demos/gtk-demo/fishbowl.ui   |  20 +++-
 demos/gtk-demo/gtkfishbowl.c | 225 ++++++++++++++++++++++++++++++++++++++++++-
 demos/gtk-demo/gtkfishbowl.h |   7 ++
 4 files changed, 249 insertions(+), 166 deletions(-)
---
diff --git a/demos/gtk-demo/fishbowl.c b/demos/gtk-demo/fishbowl.c
index 7aeaf3206e..bc4650a5dd 100644
--- a/demos/gtk-demo/fishbowl.c
+++ b/demos/gtk-demo/fishbowl.c
@@ -9,162 +9,6 @@
 
 #include "gtkfishbowl.h"
 
-GtkWidget *info_label;
-GtkWidget *allow_changes;
-
-#define N_STATS 5
-
-#define STATS_UPDATE_TIME G_USEC_PER_SEC
-
-typedef struct _Stats Stats;
-struct _Stats {
-  gint last_suggestion;
-};
-
-static Stats *
-get_stats (GtkWidget *widget)
-{
-  static GQuark stats_quark = 0;
-  Stats *stats;
-
-  if (G_UNLIKELY (stats_quark == 0))
-    stats_quark = g_quark_from_static_string ("stats");
-
-  stats = g_object_get_qdata (G_OBJECT (widget), stats_quark);
-  if (stats == NULL)
-    {
-      stats = g_new0 (Stats, 1);
-      g_object_set_qdata_full (G_OBJECT (widget), stats_quark, stats, g_free);
-    }
-
-  return stats;
-}
-
-static gint64
-guess_refresh_interval (GdkFrameClock *frame_clock)
-{
-  gint64 interval;
-  gint64 i;
-
-  interval = G_MAXINT64;
-
-  for (i = gdk_frame_clock_get_history_start (frame_clock);
-       i < gdk_frame_clock_get_frame_counter (frame_clock);
-       i++)
-    {
-      GdkFrameTimings *t, *before;
-      gint64 ts, before_ts;
-
-      t = gdk_frame_clock_get_timings (frame_clock, i);
-      before = gdk_frame_clock_get_timings (frame_clock, i - 1);
-      if (t == NULL || before == NULL)
-        continue;
-
-      ts = gdk_frame_timings_get_frame_time (t);
-      before_ts = gdk_frame_timings_get_frame_time (before);
-      if (ts == 0 || before_ts == 0)
-        continue;
-
-      interval = MIN (interval, ts - before_ts);
-    }
-
-  if (interval == G_MAXINT64)
-    return 0;
-
-  return interval;
-}
-
-static void
-do_stats (GtkWidget *widget,
-          gint      *suggested_change)
-{
-  GdkFrameClock *frame_clock;
-  Stats *stats;
-  GdkFrameTimings *start, *end;
-  gint64 start_counter, end_counter;
-  gint64 n_frames, expected_frames;
-  gint64 start_timestamp, end_timestamp;
-  gint64 interval;
-  char *new_label;
-
-  stats = get_stats (widget);
-  frame_clock = gtk_widget_get_frame_clock (widget);
-  if (frame_clock == NULL)
-    return;
-
-  start_counter = gdk_frame_clock_get_history_start (frame_clock);
-  end_counter = gdk_frame_clock_get_frame_counter (frame_clock);
-  start = gdk_frame_clock_get_timings (frame_clock, start_counter);
-  for (end = gdk_frame_clock_get_timings (frame_clock, end_counter);
-       end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
-       end = gdk_frame_clock_get_timings (frame_clock, end_counter))
-    end_counter--;
-  if (end_counter - start_counter < 4)
-    return;
-
-  start_timestamp = gdk_frame_timings_get_presentation_time (start);
-  end_timestamp = gdk_frame_timings_get_presentation_time (end);
-  if (start_timestamp == 0 || end_timestamp == 0)
-    {
-      start_timestamp = gdk_frame_timings_get_frame_time (start);
-      end_timestamp = gdk_frame_timings_get_frame_time (end);
-    }
-
-  interval = gdk_frame_timings_get_refresh_interval (end);
-  if (interval == 0)
-    {
-      interval = guess_refresh_interval (frame_clock);
-      if (interval == 0)
-        return;
-    }
-  n_frames = end_counter - start_counter;
-  expected_frames = round ((double) (end_timestamp - start_timestamp) / interval);
-
-  new_label = g_strdup_printf ("icons - %.1f fps",
-                               ((double) n_frames) * G_USEC_PER_SEC / (end_timestamp - start_timestamp));
-  gtk_label_set_label (GTK_LABEL (info_label), new_label);
-  g_free (new_label);
-
-  if (n_frames >= expected_frames)
-    {
-      if (stats->last_suggestion > 0)
-        stats->last_suggestion *= 2;
-      else
-        stats->last_suggestion = 1;
-    }
-  else if (n_frames + 1 < expected_frames)
-    {
-      if (stats->last_suggestion < 0)
-        stats->last_suggestion--;
-      else
-        stats->last_suggestion = -1;
-    }
-  else
-    {
-      stats->last_suggestion = 0;
-    }
-
-  if (suggested_change)
-    *suggested_change = stats->last_suggestion;
-  else
-    stats->last_suggestion = 0;
-}
-
-static gboolean
-move_fish (gpointer bowl)
-{
-  gint suggested_change = 0, new_count;
-  
-  do_stats (bowl,
-            !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (allow_changes)) ? &suggested_change : NULL);
-
-  new_count = gtk_fishbowl_get_count (GTK_FISHBOWL (bowl)) + suggested_change;
-  new_count = MAX (1, new_count);
-  gtk_fishbowl_set_count (GTK_FISHBOWL (bowl), new_count);
-
-  return G_SOURCE_CONTINUE;
-}
-
 GtkWidget *
 do_fishbowl (GtkWidget *do_widget)
 {
@@ -182,19 +26,12 @@ do_fishbowl (GtkWidget *do_widget)
       window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
       bowl = GTK_WIDGET (gtk_builder_get_object (builder, "bowl"));
       gtk_fishbowl_set_use_icons (GTK_FISHBOWL (bowl), TRUE);
-      info_label = GTK_WIDGET (gtk_builder_get_object (builder, "info_label"));
-      allow_changes = GTK_WIDGET (gtk_builder_get_object (builder, "changes_allow"));
       gtk_window_set_display (GTK_WINDOW (window),
                               gtk_widget_get_display (do_widget));
       g_signal_connect (window, "destroy",
                         G_CALLBACK (gtk_widget_destroyed), &window);
 
       gtk_widget_realize (window);
-      g_timeout_add_seconds_full (G_PRIORITY_DEFAULT_IDLE,
-                                  1,
-                                  move_fish,
-                                  bowl,
-                                  NULL);
     }
 
   if (!gtk_widget_get_visible (window))
diff --git a/demos/gtk-demo/fishbowl.ui b/demos/gtk-demo/fishbowl.ui
index a6899dbfa9..5cd82a6648 100644
--- a/demos/gtk-demo/fishbowl.ui
+++ b/demos/gtk-demo/fishbowl.ui
@@ -7,7 +7,24 @@
       <object class="GtkHeaderBar" id="">
         <property name="show-title-buttons">1</property>
         <child>
-          <object class="GtkLabel" id="info_label">
+          <object class="GtkLabel">
+            <property name="label">fps</property>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="label" bind-source="bowl" bind-property="framerate"/>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="label">Icons, </property>
           </object>
           <packing>
             <property name="pack-type">end</property>
@@ -48,6 +65,7 @@
       <object class="GtkFishbowl" id="bowl">
         <property name="visible">True</property>
         <property name="animating">True</property>
+        <property name="benchmark" bind-source="changes_allow" bind-property="active" 
bind-flags="invert-boolean">True</property>
       </object>
     </child>
   </object>
diff --git a/demos/gtk-demo/gtkfishbowl.c b/demos/gtk-demo/gtkfishbowl.c
index ee0b5f9365..a15f1e9470 100644
--- a/demos/gtk-demo/gtkfishbowl.c
+++ b/demos/gtk-demo/gtkfishbowl.c
@@ -28,9 +28,14 @@ struct _GtkFishbowlPrivate
   guint count;
 
   gint64 last_frame_time;
+  gint64 update_delay;
   guint tick_id;
 
-  guint use_icons: 1;
+  double framerate;
+  int last_benchmark_change;
+
+  guint use_icons : 1;
+  guint benchmark : 1;
 };
 
 struct _GtkFishbowlChild
@@ -45,7 +50,10 @@ struct _GtkFishbowlChild
 enum {
    PROP_0,
    PROP_ANIMATING,
+   PROP_BENCHMARK,
    PROP_COUNT,
+   PROP_FRAMERATE,
+   PROP_UPDATE_DELAY,
    NUM_PROPERTIES
 };
 
@@ -56,7 +64,11 @@ G_DEFINE_TYPE_WITH_PRIVATE (GtkFishbowl, gtk_fishbowl, GTK_TYPE_CONTAINER)
 static void
 gtk_fishbowl_init (GtkFishbowl *fishbowl)
 {
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
   gtk_widget_set_has_surface (GTK_WIDGET (fishbowl), FALSE);
+
+  priv->update_delay = G_USEC_PER_SEC;
 }
 
 /**
@@ -264,10 +276,18 @@ gtk_fishbowl_set_property (GObject         *object,
       gtk_fishbowl_set_animating (fishbowl, g_value_get_boolean (value));
       break;
 
+    case PROP_BENCHMARK:
+      gtk_fishbowl_set_benchmark (fishbowl, g_value_get_boolean (value));
+      break;
+
     case PROP_COUNT:
       gtk_fishbowl_set_count (fishbowl, g_value_get_uint (value));
       break;
 
+    case PROP_UPDATE_DELAY:
+      gtk_fishbowl_set_update_delay (fishbowl, g_value_get_int64 (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -288,10 +308,22 @@ gtk_fishbowl_get_property (GObject         *object,
       g_value_set_boolean (value, gtk_fishbowl_get_animating (fishbowl));
       break;
 
+    case PROP_BENCHMARK:
+      g_value_set_boolean (value, gtk_fishbowl_get_benchmark (fishbowl));
+      break;
+
     case PROP_COUNT:
       g_value_set_uint (value, gtk_fishbowl_get_count (fishbowl));
       break;
 
+    case PROP_FRAMERATE:
+      g_value_set_double (value, gtk_fishbowl_get_framerate (fishbowl));
+      break;
+
+    case PROP_UPDATE_DELAY:
+      g_value_set_int64 (value, gtk_fishbowl_get_update_delay (fishbowl));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -323,13 +355,36 @@ gtk_fishbowl_class_init (GtkFishbowlClass *klass)
                             FALSE,
                             G_PARAM_READWRITE);
 
+  props[PROP_BENCHMARK] =
+      g_param_spec_boolean ("benchmark",
+                            "Benchmark",
+                            "Adapt the count property to hit the maximum framerate",
+                            FALSE,
+                            G_PARAM_READWRITE);
+
   props[PROP_COUNT] =
       g_param_spec_uint ("count",
                          "Count",
                          "Number of widgets",
                          0, G_MAXUINT,
                          0,
-                         G_PARAM_READABLE);
+                         G_PARAM_READWRITE);
+
+  props[PROP_FRAMERATE] =
+      g_param_spec_double ("framerate",
+                           "Framerate",
+                           "Framerate of this widget in frames per second",
+                           0, G_MAXDOUBLE,
+                           0,
+                           G_PARAM_READABLE);
+
+  props[PROP_UPDATE_DELAY] =
+      g_param_spec_int64 ("update-delay",
+                          "Update delay",
+                          "Number of usecs between updates",
+                          0, G_MAXINT64,
+                          G_USEC_PER_SEC,
+                          G_PARAM_READWRITE);
 
   g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
 }
@@ -432,6 +487,30 @@ gtk_fishbowl_set_count (GtkFishbowl *fishbowl,
   g_object_thaw_notify (G_OBJECT (fishbowl));
 }
 
+gboolean
+gtk_fishbowl_get_benchmark (GtkFishbowl *fishbowl)
+{
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+  return priv->benchmark;
+}
+
+void
+gtk_fishbowl_set_benchmark (GtkFishbowl *fishbowl,
+                            gboolean     benchmark)
+{
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+  if (priv->benchmark == benchmark)
+    return;
+
+  priv->benchmark = benchmark;
+  if (!benchmark)
+    priv->last_benchmark_change = 0;
+
+  g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_BENCHMARK]);
+}
+
 gboolean
 gtk_fishbowl_get_animating (GtkFishbowl *fishbowl)
 {
@@ -440,6 +519,111 @@ gtk_fishbowl_get_animating (GtkFishbowl *fishbowl)
   return priv->tick_id != 0;
 }
 
+static gint64
+guess_refresh_interval (GdkFrameClock *frame_clock)
+{
+  gint64 interval;
+  gint64 i;
+
+  interval = G_MAXINT64;
+
+  for (i = gdk_frame_clock_get_history_start (frame_clock);
+       i < gdk_frame_clock_get_frame_counter (frame_clock);
+       i++)
+    {
+      GdkFrameTimings *t, *before;
+      gint64 ts, before_ts;
+
+      t = gdk_frame_clock_get_timings (frame_clock, i);
+      before = gdk_frame_clock_get_timings (frame_clock, i - 1);
+      if (t == NULL || before == NULL)
+        continue;
+
+      ts = gdk_frame_timings_get_frame_time (t);
+      before_ts = gdk_frame_timings_get_frame_time (before);
+      if (ts == 0 || before_ts == 0)
+        continue;
+
+      interval = MIN (interval, ts - before_ts);
+    }
+
+  if (interval == G_MAXINT64)
+    return 0;
+
+  return interval;
+}
+
+static void
+gtk_fishbowl_do_update (GtkFishbowl *fishbowl)
+{
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+  GdkFrameClock *frame_clock;
+  GdkFrameTimings *start, *end;
+  gint64 start_counter, end_counter;
+  gint64 n_frames, expected_frames;
+  gint64 start_timestamp, end_timestamp;
+  gint64 interval;
+
+  frame_clock = gtk_widget_get_frame_clock (GTK_WIDGET (fishbowl));
+  if (frame_clock == NULL)
+    return;
+
+  start_counter = gdk_frame_clock_get_history_start (frame_clock);
+  end_counter = gdk_frame_clock_get_frame_counter (frame_clock);
+  start = gdk_frame_clock_get_timings (frame_clock, start_counter);
+  for (end = gdk_frame_clock_get_timings (frame_clock, end_counter);
+       end_counter > start_counter && end != NULL && !gdk_frame_timings_get_complete (end);
+       end = gdk_frame_clock_get_timings (frame_clock, end_counter))
+    end_counter--;
+  if (end_counter - start_counter < 4)
+    return;
+
+  start_timestamp = gdk_frame_timings_get_presentation_time (start);
+  end_timestamp = gdk_frame_timings_get_presentation_time (end);
+  if (start_timestamp == 0 || end_timestamp == 0)
+    {
+      start_timestamp = gdk_frame_timings_get_frame_time (start);
+      end_timestamp = gdk_frame_timings_get_frame_time (end);
+    }
+
+  n_frames = end_counter - start_counter;
+  priv->framerate = ((double) n_frames) * G_USEC_PER_SEC / (end_timestamp - start_timestamp);
+  g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
+
+  if (!priv->benchmark)
+    return;
+
+  interval = gdk_frame_timings_get_refresh_interval (end);
+  if (interval == 0)
+    {
+      interval = guess_refresh_interval (frame_clock);
+      if (interval == 0)
+        return;
+    }
+  expected_frames = round ((double) (end_timestamp - start_timestamp) / interval);
+
+  if (n_frames >= expected_frames)
+    {
+      if (priv->last_benchmark_change > 0)
+        priv->last_benchmark_change *= 2;
+      else
+        priv->last_benchmark_change = 1;
+    }
+  else if (n_frames + 1 < expected_frames)
+    {
+      if (priv->last_benchmark_change < 0)
+        priv->last_benchmark_change--;
+      else
+        priv->last_benchmark_change = -1;
+    }
+  else
+    {
+      priv->last_benchmark_change = 0;
+    }
+
+  gtk_fishbowl_set_count (fishbowl, MAX (1, priv->count + priv->last_benchmark_change));
+}
+
 static gboolean
 gtk_fishbowl_tick (GtkWidget     *widget,
                    GdkFrameClock *frame_clock,
@@ -450,9 +634,11 @@ gtk_fishbowl_tick (GtkWidget     *widget,
   GtkFishbowlChild *child;
   GList *l;
   gint64 frame_time, elapsed;
+  gboolean do_update;
 
   frame_time = gdk_frame_clock_get_frame_time (gtk_widget_get_frame_clock (widget));
   elapsed = frame_time - priv->last_frame_time;
+  do_update = frame_time / priv->update_delay != priv->last_frame_time / priv->update_delay;
   priv->last_frame_time = frame_time;
 
   /* last frame was 0, so we're just starting to animate */
@@ -491,6 +677,9 @@ gtk_fishbowl_tick (GtkWidget     *widget,
 
   gtk_widget_queue_allocate (widget);
 
+  if (do_update)
+    gtk_fishbowl_do_update (fishbowl);
+
   return G_SOURCE_CONTINUE;
 }
 
@@ -515,8 +704,40 @@ gtk_fishbowl_set_animating (GtkFishbowl *fishbowl,
       priv->last_frame_time = 0;
       gtk_widget_remove_tick_callback (GTK_WIDGET (fishbowl), priv->tick_id);
       priv->tick_id = 0;
+      priv->framerate = 0;
+      g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_FRAMERATE]);
     }
 
   g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_ANIMATING]);
 }
 
+double
+gtk_fishbowl_get_framerate (GtkFishbowl *fishbowl)
+{
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+  return priv->framerate;
+}
+
+gint64
+gtk_fishbowl_get_update_delay (GtkFishbowl *fishbowl)
+{
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+  return priv->update_delay;
+}
+
+void
+gtk_fishbowl_set_update_delay (GtkFishbowl *fishbowl,
+                               gint64       update_delay)
+{
+  GtkFishbowlPrivate *priv = gtk_fishbowl_get_instance_private (fishbowl);
+
+  if (priv->update_delay == update_delay)
+    return;
+
+  priv->update_delay = update_delay;
+
+  g_object_notify_by_pspec (G_OBJECT (fishbowl), props[PROP_UPDATE_DELAY]);
+}
+
diff --git a/demos/gtk-demo/gtkfishbowl.h b/demos/gtk-demo/gtkfishbowl.h
index b1559d0b26..83f2c249d7 100644
--- a/demos/gtk-demo/gtkfishbowl.h
+++ b/demos/gtk-demo/gtkfishbowl.h
@@ -55,6 +55,13 @@ void       gtk_fishbowl_set_count         (GtkFishbowl       *fishbowl,
 gboolean   gtk_fishbowl_get_animating     (GtkFishbowl       *fishbowl);
 void       gtk_fishbowl_set_animating     (GtkFishbowl       *fishbowl,
                                            gboolean           animating);
+gboolean   gtk_fishbowl_get_benchmark     (GtkFishbowl       *fishbowl);
+void       gtk_fishbowl_set_benchmark     (GtkFishbowl       *fishbowl,
+                                           gboolean           animating);
+double     gtk_fishbowl_get_framerate     (GtkFishbowl       *fishbowl);
+gint64     gtk_fishbowl_get_update_delay  (GtkFishbowl       *fishbowl);
+void       gtk_fishbowl_set_update_delay  (GtkFishbowl       *fishbowl,
+                                           gint64             update_delay);
 
 G_END_DECLS
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]