~ubuntu-branches/ubuntu/karmic/gtk+2.0/karmic-proposed

1.1.21 by Sebastien Bacher
Import upstream version 2.10.12
1
README for gtk+/perf
2
--------------------
3
4
This is a framework for testing performance in GTK+.   For GTK+, being
5
performant does not only mean "paint widgets fast".  It also means
6
things like the time needed to set up widgets, to map and draw a
7
window for the first time, and emitting/propagating signals.
8
9
The following is accurate as of 2006/Jun/14.
10
11
12
Background
13
----------
14
15
A widget's lifetime looks more or less like this:
16
17
	1. Instantiation
18
	2. Size request
19
	3. Size allocate
20
	5. Realize
21
	4. Map
22
	5. Expose
23
	6. Destroy
24
25
Some of these stages are particularly interesting:
26
27
- Instantiation means creating the widget.  This may be as simple as a
28
  few malloc()s and setting some fields.  It could also be a
29
  complicated operation if the widget needs to contact an external
30
  server to create itself, or if it needs to read data files.
31
32
- Size requisition is when GTK+ asks the widget, "how big do you want
33
  to be on the screen"?  This can be an expensive operation.  The
34
  widget has to measure its text, measure its icons (and thus load its
35
  icons), and generally run through its internal layout code.
36
37
- Realization is when the widget creates its GDK resources, like its
38
  GdkWindow and graphics contexts it may need.  This could be
39
  expensive if the widget needs to load data files for cursors or
40
  backgrounds.
41
42
- Expose is when the widget gets repainted.  This will happen many
43
  times throughout the lifetime of the widget:  every time you drag a
44
  window on top of it, every time its data changes and it needs to
45
  redraw, every time it gets resized.
46
47
GtkWidgetProfiler is a mechanism to let you get individual timings for
48
each of the stages in the lifetime of a widget.  It also lets you run
49
some stages many times in a sequence, so that you can run a real
50
profiler and get an adequate number of samples.  For example,
51
GtkWidgetProfiler lets you say "repaint this widget 1000 times".
52
53
Why is this not as simple as doing
54
55
	start_timer ();
56
	for (i = 0; i < 1000; i++) {
57
		gtk_widget_queue_draw (widget);
58
		while (gtk_events_pending ())
59
			gtk_main_iteration ();
60
	}
61
	stop_timer ();
62
63
Huh?
64
65
Because X is an asynchronous window system.  So, when you send the
66
"paint" commands, your program will regain control but it will take
67
some time for the X server to actually process those commands.
68
GtkWidgetProfiler has special code to wait for the X server and give
69
you accurate timings.
70
71
72
Using the framework
73
-------------------
74
75
Right now the framework is very simple; it just has utility functions
76
to time widget creation, mapping, exposure, and destruction.  To run
77
such a test, you use the GtkWidgetProfiler object in
78
gtkwidgetprofiler.h.
79
80
The gtk_widget_profiler_profile_boot() function will emit the
81
"create-widget" signal so that you can create your widget for
82
testing.  It will then take timings for the widget, and emit the
83
"report" signal as appropriate.
84
85
The "create-widget" signal:
86
87
  The handler has this form:
88
89
    GtkWidget *create_widget_callback (GtkWidgetProfiler *profiler, 
90
				       gpointer user_data);
91
92
  You need to create a widget in your handler, and return it.  Do not
93
  show the widget; the profiler will do that by itself at the right
94
  time, and will actually complain if you show the widget.
95
96
97
The "report" signal:
98
99
  This function will get called when the profiler wants to report that
100
  it finished timing an important stage in the lifecycle of your
101
  widget.  The handler has this form:
102
103
    void report_callback (GtkWidgetProfiler      *profiler,
104
			  GtkWidgetProfilerReport report,
105
			  GtkWidget              *widget,
106
			  gdouble                 elapsed,
107
			  gpointer                user_data);
108
109
  The "report" argument tells you what happened to your widget:
110
111
    GTK_WIDGET_PROFILER_REPORT_CREATE.  A timer gets started right
112
    before the profiler emits the "create-widget" signal,, and it gets
113
    stopped when your callback returns with the new widget.  This
114
    measures the time it takes to set up your widget, but not show it.
115
116
    GTK_WIDGET_PROFILER_REPORT_MAP.  A timer gets started right before
117
    the profiler calls gtk_widget_show_all() on your widget, and it
118
    gets stopped when the the widget has been mapped.
119
120
    GTK_WIDGET_PROFILER_REPORT_EXPOSE.  A timer gets started right before
121
    the profiler starts waiting for GTK+ and the X server to finish
122
    painting your widget, and it gets stopped when the widget is fully
123
    painted to the screen.
124
125
    GTK_WIDGET_PROFILER_REPORT_DESTROY.  A timer gets started right
126
    before the profiler calls gtk_widget_destroy() on your widget, and
127
    it gets stopped when gtk_widget_destroy() returns.
128
129
As a very basic example of using GtkWidgetProfiler is this:
130
131
----------------------------------------------------------------------
132
#include <stdio.h>
133
#include <gtk/gtk.h>
134
#include "gtkwidgetprofiler.h"
135
136
static GtkWidget *
137
create_widget_cb (GtkWidgetProfiler *profiler, gpointer data)
138
{
139
  GtkWidget *window;
140
141
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
142
  /* ... fill the window with widgets, and don't show them ... */
143
144
  return window;
145
}
146
147
static void
148
report_cb (GtkWidgetProfiler *profiler, GtkWidgetProfilerReport report, GtkWidget *widget, gdouble elapsed, gpointer data)
149
{
150
  const char *type;
151
152
  switch (report) {
153
  case GTK_WIDGET_PROFILER_REPORT_CREATE:
154
    type = "widget creation";
155
    break;
156
157
  case GTK_WIDGET_PROFILER_REPORT_MAP:
158
    type = "widget map";
159
    break;
160
161
  case GTK_WIDGET_PROFILER_REPORT_EXPOSE:
162
    type = "widget expose";
163
    break;
164
165
  case GTK_WIDGET_PROFILER_REPORT_DESTROY:
166
    type = "widget destruction";
167
    break;
168
169
  default:
170
    g_assert_not_reached ();
171
    type = NULL;
172
  }
173
174
  fprintf (stderr, "%s: %g sec\n", type, elapsed);
175
176
  if (report == GTK_WIDGET_PROFILER_REPORT_DESTROY)
177
    fputs ("\n", stderr);
178
}
179
180
int
181
main (int argc, char **argv)
182
{
183
  GtkWidgetProfiler *profiler;
184
185
  gtk_init (&argc, &argv);
186
187
  profiler = gtk_widget_profiler_new ();
188
  g_signal_connect (profiler, "create-widget",
189
		    G_CALLBACK (create_widget_cb), NULL);
190
  g_signal_connect (profiler, "report",
191
		    G_CALLBACK (report_cb), NULL);
192
193
  gtk_widget_profiler_set_num_iterations (profiler, 100);
194
  gtk_widget_profiler_profile_boot (profiler);
195
196
  gtk_widget_profiler_profile_expose (profiler);
197
  
198
  return 0;
199
}
200
201
----------------------------------------------------------------------
202
203
204
Getting meaningful results
205
--------------------------
206
207
Getting times for widget creation/mapping/exposing/destruction is
208
interesting, but how do you actually find the places that need
209
optimizing?
210
211
Why, you run the tests under a profiler, of course.
212
213
FIXME: document how to do this.
214
215
216
Feedback
217
--------
218
219
Please mail your feedback to Federico Mena-Quintero <federico@novell.com>.
220
This performance framework is a work in progress.