Blame perf/README

Packit Service fb6fa5
README for gtk+/perf
Packit Service fb6fa5
--------------------
Packit Service fb6fa5
Packit Service fb6fa5
This is a framework for testing performance in GTK+.   For GTK+, being
Packit Service fb6fa5
performant does not only mean "paint widgets fast".  It also means
Packit Service fb6fa5
things like the time needed to set up widgets, to map and draw a
Packit Service fb6fa5
window for the first time, and emitting/propagating signals.
Packit Service fb6fa5
Packit Service fb6fa5
The following is accurate as of 2006/Jun/14.
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
Background
Packit Service fb6fa5
----------
Packit Service fb6fa5
Packit Service fb6fa5
A widget's lifetime looks more or less like this:
Packit Service fb6fa5
Packit Service fb6fa5
	1. Instantiation
Packit Service fb6fa5
	2. Size request
Packit Service fb6fa5
	3. Size allocate
Packit Service fb6fa5
	5. Realize
Packit Service fb6fa5
	4. Map
Packit Service fb6fa5
	5. Expose
Packit Service fb6fa5
	6. Destroy
Packit Service fb6fa5
Packit Service fb6fa5
Some of these stages are particularly interesting:
Packit Service fb6fa5
Packit Service fb6fa5
- Instantiation means creating the widget.  This may be as simple as a
Packit Service fb6fa5
  few malloc()s and setting some fields.  It could also be a
Packit Service fb6fa5
  complicated operation if the widget needs to contact an external
Packit Service fb6fa5
  server to create itself, or if it needs to read data files.
Packit Service fb6fa5
Packit Service fb6fa5
- Size requisition is when GTK+ asks the widget, "how big do you want
Packit Service fb6fa5
  to be on the screen"?  This can be an expensive operation.  The
Packit Service fb6fa5
  widget has to measure its text, measure its icons (and thus load its
Packit Service fb6fa5
  icons), and generally run through its internal layout code.
Packit Service fb6fa5
Packit Service fb6fa5
- Realization is when the widget creates its GDK resources, like its
Packit Service fb6fa5
  GdkWindow and graphics contexts it may need.  This could be
Packit Service fb6fa5
  expensive if the widget needs to load data files for cursors or
Packit Service fb6fa5
  backgrounds.
Packit Service fb6fa5
Packit Service fb6fa5
- Expose is when the widget gets repainted.  This will happen many
Packit Service fb6fa5
  times throughout the lifetime of the widget:  every time you drag a
Packit Service fb6fa5
  window on top of it, every time its data changes and it needs to
Packit Service fb6fa5
  redraw, every time it gets resized.
Packit Service fb6fa5
Packit Service fb6fa5
GtkWidgetProfiler is a mechanism to let you get individual timings for
Packit Service fb6fa5
each of the stages in the lifetime of a widget.  It also lets you run
Packit Service fb6fa5
some stages many times in a sequence, so that you can run a real
Packit Service fb6fa5
profiler and get an adequate number of samples.  For example,
Packit Service fb6fa5
GtkWidgetProfiler lets you say "repaint this widget 1000 times".
Packit Service fb6fa5
Packit Service fb6fa5
Why is this not as simple as doing
Packit Service fb6fa5
Packit Service fb6fa5
	start_timer ();
Packit Service fb6fa5
	for (i = 0; i < 1000; i++) {
Packit Service fb6fa5
		gtk_widget_queue_draw (widget);
Packit Service fb6fa5
		while (gtk_events_pending ())
Packit Service fb6fa5
			gtk_main_iteration ();
Packit Service fb6fa5
	}
Packit Service fb6fa5
	stop_timer ();
Packit Service fb6fa5
Packit Service fb6fa5
Huh?
Packit Service fb6fa5
Packit Service fb6fa5
Because X is an asynchronous window system.  So, when you send the
Packit Service fb6fa5
"paint" commands, your program will regain control but it will take
Packit Service fb6fa5
some time for the X server to actually process those commands.
Packit Service fb6fa5
GtkWidgetProfiler has special code to wait for the X server and give
Packit Service fb6fa5
you accurate timings.
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
Using the framework
Packit Service fb6fa5
-------------------
Packit Service fb6fa5
Packit Service fb6fa5
Right now the framework is very simple; it just has utility functions
Packit Service fb6fa5
to time widget creation, mapping, exposure, and destruction.  To run
Packit Service fb6fa5
such a test, you use the GtkWidgetProfiler object in
Packit Service fb6fa5
gtkwidgetprofiler.h.
Packit Service fb6fa5
Packit Service fb6fa5
The gtk_widget_profiler_profile_boot() function will emit the
Packit Service fb6fa5
"create-widget" signal so that you can create your widget for
Packit Service fb6fa5
testing.  It will then take timings for the widget, and emit the
Packit Service fb6fa5
"report" signal as appropriate.
Packit Service fb6fa5
Packit Service fb6fa5
The "create-widget" signal:
Packit Service fb6fa5
Packit Service fb6fa5
  The handler has this form:
Packit Service fb6fa5
Packit Service fb6fa5
    GtkWidget *create_widget_callback (GtkWidgetProfiler *profiler, 
Packit Service fb6fa5
				       gpointer user_data);
Packit Service fb6fa5
Packit Service fb6fa5
  You need to create a widget in your handler, and return it.  Do not
Packit Service fb6fa5
  show the widget; the profiler will do that by itself at the right
Packit Service fb6fa5
  time, and will actually complain if you show the widget.
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
The "report" signal:
Packit Service fb6fa5
Packit Service fb6fa5
  This function will get called when the profiler wants to report that
Packit Service fb6fa5
  it finished timing an important stage in the lifecycle of your
Packit Service fb6fa5
  widget.  The handler has this form:
Packit Service fb6fa5
Packit Service fb6fa5
    void report_callback (GtkWidgetProfiler      *profiler,
Packit Service fb6fa5
			  GtkWidgetProfilerReport report,
Packit Service fb6fa5
			  GtkWidget              *widget,
Packit Service fb6fa5
			  gdouble                 elapsed,
Packit Service fb6fa5
			  gpointer                user_data);
Packit Service fb6fa5
Packit Service fb6fa5
  The "report" argument tells you what happened to your widget:
Packit Service fb6fa5
Packit Service fb6fa5
    GTK_WIDGET_PROFILER_REPORT_CREATE.  A timer gets started right
Packit Service fb6fa5
    before the profiler emits the "create-widget" signal,, and it gets
Packit Service fb6fa5
    stopped when your callback returns with the new widget.  This
Packit Service fb6fa5
    measures the time it takes to set up your widget, but not show it.
Packit Service fb6fa5
Packit Service fb6fa5
    GTK_WIDGET_PROFILER_REPORT_MAP.  A timer gets started right before
Packit Service fb6fa5
    the profiler calls gtk_widget_show_all() on your widget, and it
Packit Service fb6fa5
    gets stopped when the the widget has been mapped.
Packit Service fb6fa5
Packit Service fb6fa5
    GTK_WIDGET_PROFILER_REPORT_EXPOSE.  A timer gets started right before
Packit Service fb6fa5
    the profiler starts waiting for GTK+ and the X server to finish
Packit Service fb6fa5
    painting your widget, and it gets stopped when the widget is fully
Packit Service fb6fa5
    painted to the screen.
Packit Service fb6fa5
Packit Service fb6fa5
    GTK_WIDGET_PROFILER_REPORT_DESTROY.  A timer gets started right
Packit Service fb6fa5
    before the profiler calls gtk_widget_destroy() on your widget, and
Packit Service fb6fa5
    it gets stopped when gtk_widget_destroy() returns.
Packit Service fb6fa5
Packit Service fb6fa5
As a very basic example of using GtkWidgetProfiler is this:
Packit Service fb6fa5
Packit Service fb6fa5
----------------------------------------------------------------------
Packit Service fb6fa5
#include <stdio.h>
Packit Service fb6fa5
#include <gtk/gtk.h>
Packit Service fb6fa5
#include "gtkwidgetprofiler.h"
Packit Service fb6fa5
Packit Service fb6fa5
static GtkWidget *
Packit Service fb6fa5
create_widget_cb (GtkWidgetProfiler *profiler, gpointer data)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkWidget *window;
Packit Service fb6fa5
Packit Service fb6fa5
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
Packit Service fb6fa5
  /* ... fill the window with widgets, and don't show them ... */
Packit Service fb6fa5
Packit Service fb6fa5
  return window;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
static void
Packit Service fb6fa5
report_cb (GtkWidgetProfiler *profiler, GtkWidgetProfilerReport report, GtkWidget *widget, gdouble elapsed, gpointer data)
Packit Service fb6fa5
{
Packit Service fb6fa5
  const char *type;
Packit Service fb6fa5
Packit Service fb6fa5
  switch (report) {
Packit Service fb6fa5
  case GTK_WIDGET_PROFILER_REPORT_CREATE:
Packit Service fb6fa5
    type = "widget creation";
Packit Service fb6fa5
    break;
Packit Service fb6fa5
Packit Service fb6fa5
  case GTK_WIDGET_PROFILER_REPORT_MAP:
Packit Service fb6fa5
    type = "widget map";
Packit Service fb6fa5
    break;
Packit Service fb6fa5
Packit Service fb6fa5
  case GTK_WIDGET_PROFILER_REPORT_EXPOSE:
Packit Service fb6fa5
    type = "widget expose";
Packit Service fb6fa5
    break;
Packit Service fb6fa5
Packit Service fb6fa5
  case GTK_WIDGET_PROFILER_REPORT_DESTROY:
Packit Service fb6fa5
    type = "widget destruction";
Packit Service fb6fa5
    break;
Packit Service fb6fa5
Packit Service fb6fa5
  default:
Packit Service fb6fa5
    g_assert_not_reached ();
Packit Service fb6fa5
    type = NULL;
Packit Service fb6fa5
  }
Packit Service fb6fa5
Packit Service fb6fa5
  fprintf (stderr, "%s: %g sec\n", type, elapsed);
Packit Service fb6fa5
Packit Service fb6fa5
  if (report == GTK_WIDGET_PROFILER_REPORT_DESTROY)
Packit Service fb6fa5
    fputs ("\n", stderr);
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
int
Packit Service fb6fa5
main (int argc, char **argv)
Packit Service fb6fa5
{
Packit Service fb6fa5
  GtkWidgetProfiler *profiler;
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_init (&argc, &argv);
Packit Service fb6fa5
Packit Service fb6fa5
  profiler = gtk_widget_profiler_new ();
Packit Service fb6fa5
  g_signal_connect (profiler, "create-widget",
Packit Service fb6fa5
		    G_CALLBACK (create_widget_cb), NULL);
Packit Service fb6fa5
  g_signal_connect (profiler, "report",
Packit Service fb6fa5
		    G_CALLBACK (report_cb), NULL);
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_widget_profiler_set_num_iterations (profiler, 100);
Packit Service fb6fa5
  gtk_widget_profiler_profile_boot (profiler);
Packit Service fb6fa5
Packit Service fb6fa5
  gtk_widget_profiler_profile_expose (profiler);
Packit Service fb6fa5
  
Packit Service fb6fa5
  return 0;
Packit Service fb6fa5
}
Packit Service fb6fa5
Packit Service fb6fa5
----------------------------------------------------------------------
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
Getting meaningful results
Packit Service fb6fa5
--------------------------
Packit Service fb6fa5
Packit Service fb6fa5
Getting times for widget creation/mapping/exposing/destruction is
Packit Service fb6fa5
interesting, but how do you actually find the places that need
Packit Service fb6fa5
optimizing?
Packit Service fb6fa5
Packit Service fb6fa5
Why, you run the tests under a profiler, of course.
Packit Service fb6fa5
Packit Service fb6fa5
FIXME: document how to do this.
Packit Service fb6fa5
Packit Service fb6fa5
Packit Service fb6fa5
Feedback
Packit Service fb6fa5
--------
Packit Service fb6fa5
Packit Service fb6fa5
Please mail your feedback to Federico Mena-Quintero <federico@novell.com>.
Packit Service fb6fa5
This performance framework is a work in progress.