Commit 4b4c0fe8 authored by Federico Mena Quintero's avatar Federico Mena Quintero Committed by Federico Mena Quintero

New directory with the start of a framework for testing performance in

2005-07-26  Federico Mena Quintero  <federico@ximian.com>

	* perf/: New directory with the start of a framework for testing
	performance in GTK+.

	* Makefile.am (SRC_SUBDIRS): Added the perf directory.

	* configure.in (AC_OUTPUT): Generate perf/Makefile.
parent 98a1367a
2005-07-26 Federico Mena Quintero <federico@ximian.com>
* perf/: New directory with the start of a framework for testing
performance in GTK+.
* Makefile.am (SRC_SUBDIRS): Added the perf directory.
* configure.in (AC_OUTPUT): Generate perf/Makefile.
2005-07-26 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfilechooserdefault.c: Fix up includes on Win32.
......
2005-07-26 Federico Mena Quintero <federico@ximian.com>
* perf/: New directory with the start of a framework for testing
performance in GTK+.
* Makefile.am (SRC_SUBDIRS): Added the perf directory.
* configure.in (AC_OUTPUT): Generate perf/Makefile.
2005-07-26 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfilechooserdefault.c: Fix up includes on Win32.
......
2005-07-26 Federico Mena Quintero <federico@ximian.com>
* perf/: New directory with the start of a framework for testing
performance in GTK+.
* Makefile.am (SRC_SUBDIRS): Added the perf directory.
* configure.in (AC_OUTPUT): Generate perf/Makefile.
2005-07-26 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkfilechooserdefault.c: Fix up includes on Win32.
......
## Makefile.am for GTK+
SRC_SUBDIRS = gdk-pixbuf gdk gtk modules demos tests contrib
SRC_SUBDIRS = gdk-pixbuf gdk gtk modules demos tests perf contrib
SUBDIRS = po po-properties $(SRC_SUBDIRS) docs m4macros
# require automake 1.4
......
......@@ -1715,6 +1715,7 @@ modules/engines/pixbuf/Makefile
modules/engines/ms-windows/Makefile
modules/engines/ms-windows/Theme/Makefile
modules/engines/ms-windows/Theme/gtk-2.0/Makefile
perf/Makefile
contrib/Makefile
contrib/gdk-pixbuf-xlib/Makefile
contrib/gdk-pixbuf-xlib/gdk-pixbuf-xlib-2.0.pc
......
## Makefile.am for gtk+/perf
INCLUDES = \
-I$(top_srcdir) \
-I$(top_builddir)/gdk \
-I$(top_srcdir)/gdk \
-DG_DISABLE_DEPRECATED \
-DGDK_PIXBUF_DISABLE_DEPRECATED \
-DGDK_DISABLE_DEPRECATED \
-DGTK_DISABLE_DEPRECATED \
$(GTK_DEBUG_FLAGS) \
$(GTK_DEP_CFLAGS)
DEPS = \
$(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GTK_API_VERSION).la \
$(top_builddir)/gdk/$(gdktargetlib) \
$(top_builddir)/gtk/$(gtktargetlib)
LDADDS = \
$(top_builddir)/gdk-pixbuf/libgdk_pixbuf-$(GTK_API_VERSION).la \
$(top_builddir)/gdk/$(gdktargetlib) \
$(top_builddir)/gtk/$(gtktargetlib)
noinst_PROGRAMS = \
testperf
testperf_DEPENDENCIES = $(TEST_DEPS)
testperf_LDADD = $(LDADDS)
testperf_SOURCES = \
appwindow.c \
appwindow.h \
main.c \
timers.c \
timers.h
EXTRA_DIST = \
README
README for gtk+/perf
--------------------
This is a framework for testing performance in GTK+. For GTK+, being
performant does not only mean "paint widgets fast". It also means
things like the time needed to set up widgets, to map and draw a
window for the first time, and emitting/propagating signals.
The following is accurate as of 2005/07/26.
Using the framework
-------------------
Right now the framework is very simple; it just has utility functions
to time widget creation, drawing, and destruction. To run such a
test, you use the functions in timers.h. You can call this:
timer_time_widget (create_func, report_func, user_data);
You must provide the create_funcn and report_func callbacks.
The create_func:
This simply creates a toplevel window with some widgets inside it.
It is important that you do not show any of the widgets; the
framework will call gtk_widget_show_all() on the toplevel window
automatically at the right time.
The report_func:
This function will get called when timer_time_widget() reaches an
interesting point in the lifecycle of your widget. See timers.h and
the TimerReport enumeration; this is what gets passed as the
"report" argument to your report_func. Right now, your function
will be called three times for each call to timer_time_widget():
1. With report = TIMER_REPORT_WIDGET_CREATION. A timer gets
started right before timer_time_widget() calls create_func,
and it gets stopped when your create_func returns. This
measures the time it takes to set up a toplevel window (but
not show it).
2. With report = TIMER_REPORT_WIDGET_SHOW. A timer gets started
right before timer_time_widget() calls gtk_widget_show_all()
on your toplevel window, and it gets stopped when the window
has been fully shown and painted to the screen.
3. With report = TIMER_REPORT_WIDGET_DESTRUCTION. A timer gets
started right before timer_time_widget() calls
gtk_widget_destroy() on your toplevel window, and it gets
stopped when gtk_widget_destroy() returns.
As a very basic example of using timer_time_widget(), you can use
something like this:
----------------------------------------------------------------------
#include <stdio.h>
#include <gtk/gtk.h>
#include "timers.h"
#define ITERS 20
static GtkWidget *
create_cb (gpointer data)
{
GtkWidget *window;
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
/* ... fill the window with widgets, and don't show them ... */
return window;
}
static void
report_cb (TimerReport report, gdouble elapsed, gpointer data)
{
const char *type;
switch (report) {
case TIMER_REPORT_WIDGET_CREATION:
type = "widget creation";
break;
case TIMER_REPORT_WIDGET_SHOW:
type = "widget show";
break;
case TIMER_REPORT_WIDGET_DESTRUCTION:
type = "widget destruction";
break;
}
fprintf (stderr, "%s: %g sec\n", type, elapsed);
}
int
main (int argc, char **argv)
{
int i;
gtk_init (&argc, &argv);
for (i = 0; i < ITERS; i++)
timer_time_widget (create_cb, report_cb, NULL);
return 0;
}
----------------------------------------------------------------------
Getting meaningful results
--------------------------
Getting times for widget creation/drawing/destruction is interesting,
but how do you actually find the places that need optimizing?
Why, you run the tests under a profiler, of course.
FIXME: document how to do this.
Feedback
--------
Please mail your feedback to Federico Mena-Quintero <federico@novell.com>.
This performance framework is a work in progress.
This diff is collapsed.
#include <gtk/gtkwidget.h>
GtkWidget *appwindow_new (void);
#include <stdio.h>
#include <gtk/gtk.h>
#include "appwindow.h"
#include "timers.h"
#define ITERS 20
static GtkWidget *
create_cb (gpointer data)
{
return appwindow_new ();
}
static void
report_cb (TimerReport report, gdouble elapsed, gpointer data)
{
const char *type;
switch (report) {
case TIMER_REPORT_WIDGET_CREATION:
type = "widget creation";
break;
case TIMER_REPORT_WIDGET_SHOW:
type = "widget show";
break;
case TIMER_REPORT_WIDGET_DESTRUCTION:
type = "widget destruction";
break;
default:
g_assert_not_reached ();
type = NULL;
}
fprintf (stderr, "%s: %g sec\n", type, elapsed);
if (report == TIMER_REPORT_WIDGET_DESTRUCTION)
fputs ("\n", stderr);
}
int
main (int argc, char **argv)
{
int i;
gtk_init (&argc, &argv);
for (i = 0; i < ITERS; i++)
timer_time_widget (create_cb, report_cb, NULL);
return 0;
}
/* Utility functions for timing widgets
*
* Authors:
* Federico Mena-Quintero <federico@novell.com>
*
* To measure how long it takes to fully map and expose a toplevel window, we
* use a trick which Owen Taylor described on IRC one day:
*
* 1. Start a timer.
* 2. Call gtk_widget_show_all() on the toplevel window.
* 3. In the expose_event handler of the window, queue an idle handler with
* G_PRIORITY_HIGH.
* 4. In the idle handler, change a property on the toplevel window.
* 5. In the property_notify_event handler, stop the timer.
*/
#include <string.h>
#include <glib.h>
#include <gtk/gtkmain.h>
#include "timers.h"
struct timer_closure
{
GTimer *timer;
GtkWidget *widget;
TimerReportFunc report_func;
gpointer user_data;
};
static gboolean
widget_property_notify_event_cb (GtkWidget *widget, GdkEventProperty *event, gpointer data)
{
struct timer_closure *closure;
gdouble elapsed;
closure = data;
if (event->atom != gdk_atom_intern ("window_property_change", FALSE))
return FALSE;
/* Finish timing map/expose */
elapsed = g_timer_elapsed (closure->timer, NULL);
(* closure->report_func) (TIMER_REPORT_WIDGET_SHOW, elapsed, closure->user_data);
/* Time destruction */
g_timer_reset (closure->timer);
gtk_widget_destroy (widget);
elapsed = g_timer_elapsed (closure->timer, NULL);
(* closure->report_func) (TIMER_REPORT_WIDGET_DESTRUCTION, elapsed, closure->user_data);
gtk_main_quit (); /* This will get us back to the end of timer_time_widget() */
return TRUE;
}
static gboolean
idle_after_expose_cb (gpointer data)
{
struct timer_closure *closure;
closure = data;
gdk_property_change (closure->widget->window,
gdk_atom_intern ("window_property_change", FALSE),
gdk_atom_intern ("STRING", FALSE),
8,
GDK_PROP_MODE_REPLACE,
"hello",
strlen ("hello"));
return FALSE;
}
static gboolean
widget_expose_event_cb (GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
struct timer_closure *closure;
closure = data;
g_idle_add_full (G_PRIORITY_HIGH, idle_after_expose_cb, closure, NULL);
return FALSE;
}
static void
instrument_widget (GtkWidget *widget,
struct timer_closure *closure)
{
g_signal_connect (widget, "expose-event",
G_CALLBACK (widget_expose_event_cb), closure);
gtk_widget_add_events (widget, GDK_PROPERTY_CHANGE_MASK);
g_signal_connect (widget, "property-notify-event",
G_CALLBACK (widget_property_notify_event_cb), closure);
}
void
timer_time_widget (TimerWidgetCreateFunc create_func,
TimerReportFunc report_func,
gpointer user_data)
{
GTimer *timer;
GtkWidget *widget;
gdouble elapsed;
struct timer_closure closure;
g_assert (create_func != NULL);
g_assert (report_func != NULL);
/* Time creation */
timer = g_timer_new ();
widget = (* create_func) (user_data);
g_assert (widget != NULL);
g_assert (!GTK_WIDGET_VISIBLE (widget) && !GTK_WIDGET_MAPPED (widget));
elapsed = g_timer_elapsed (timer, NULL);
(* report_func) (TIMER_REPORT_WIDGET_CREATION, elapsed, user_data);
/* Start timing map/expose */
closure.timer = timer;
closure.widget = widget;
closure.report_func = report_func;
closure.user_data = user_data;
instrument_widget (widget, &closure);
g_timer_reset (timer);
gtk_widget_show_all (widget);
gtk_main ();
/* Expose time and destruction time get recorded in widget_property_notify_event_cb() */
}
#include <gtk/gtkwidget.h>
typedef enum
{
TIMER_REPORT_WIDGET_CREATION,
TIMER_REPORT_WIDGET_SHOW,
TIMER_REPORT_WIDGET_DESTRUCTION
} TimerReport;
typedef GtkWidget *(* TimerWidgetCreateFunc) (gpointer user_data);
typedef void (* TimerReportFunc) (TimerReport report, gdouble elapsed, gpointer user_data);
void timer_time_widget (TimerWidgetCreateFunc create_func,
TimerReportFunc report_func,
gpointer user_data);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment