[gtk] demo: Move benchmarking implementation to fishbowl widget
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk] demo: Move benchmarking implementation to fishbowl widget
- Date: Tue, 24 Apr 2018 20:20:32 +0000 (UTC)
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]