Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * Copyright (C) 2009 Red Hat, Inc.
3 : : *
4 : : * This library is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * This library is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : : * Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General
15 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include <math.h>
19 : : #include <string.h>
20 : : #include <glib-object.h>
21 : : #include "../testcommon.h"
22 : :
23 : : #define DEFAULT_TEST_TIME 2 /* seconds */
24 : :
25 : : static GType
26 : 7 : simple_register_class (const char *name, GType parent, ...)
27 : : {
28 : 7 : GInterfaceInfo interface_info = { NULL, NULL, NULL };
29 : : va_list args;
30 : : GType type, interface;
31 : :
32 : 7 : va_start (args, parent);
33 : 7 : type = g_type_register_static_simple (parent, name, sizeof (GObjectClass),
34 : : NULL, parent == G_TYPE_INTERFACE ? 0 : sizeof (GObject), NULL, 0);
35 : : for (;;)
36 : : {
37 : 12 : interface = va_arg (args, GType);
38 : 12 : if (interface == 0)
39 : 7 : break;
40 : 5 : g_type_add_interface_static (type, interface, &interface_info);
41 : : }
42 : 7 : va_end (args);
43 : :
44 : 7 : return type;
45 : : }
46 : :
47 : : /* test emulating liststore behavior for interface lookups */
48 : :
49 : : static GType liststore;
50 : : static GType liststore_interfaces[6];
51 : :
52 : : static gpointer
53 : 3 : register_types (void)
54 : : {
55 : : static gsize inited = 0;
56 : 3 : if (g_once_init_enter (&inited))
57 : : {
58 : 1 : liststore_interfaces[0] = simple_register_class ("GtkBuildable", G_TYPE_INTERFACE, 0);
59 : 1 : liststore_interfaces[1] = simple_register_class ("GtkTreeDragDest", G_TYPE_INTERFACE, 0);
60 : 1 : liststore_interfaces[2] = simple_register_class ("GtkTreeModel", G_TYPE_INTERFACE, 0);
61 : 1 : liststore_interfaces[3] = simple_register_class ("GtkTreeDragSource", G_TYPE_INTERFACE, 0);
62 : 1 : liststore_interfaces[4] = simple_register_class ("GtkTreeSortable", G_TYPE_INTERFACE, 0);
63 : 1 : liststore_interfaces[5] = simple_register_class ("UnrelatedInterface", G_TYPE_INTERFACE, 0);
64 : :
65 : 1 : liststore = simple_register_class ("GtkListStore", G_TYPE_OBJECT,
66 : : liststore_interfaces[0], liststore_interfaces[1], liststore_interfaces[2],
67 : : liststore_interfaces[3], liststore_interfaces[4], (GType) 0);
68 : :
69 : 1 : g_once_init_leave (&inited, 1);
70 : : }
71 : 3 : return NULL;
72 : : }
73 : :
74 : : static void
75 : 1 : liststore_is_a_run (gpointer data)
76 : : {
77 : : guint i;
78 : :
79 : 1001 : for (i = 0; i < 1000; i++)
80 : : {
81 : 1000 : g_assert (g_type_is_a (liststore, liststore_interfaces[0]));
82 : 1000 : g_assert (g_type_is_a (liststore, liststore_interfaces[1]));
83 : 1000 : g_assert (g_type_is_a (liststore, liststore_interfaces[2]));
84 : 1000 : g_assert (g_type_is_a (liststore, liststore_interfaces[3]));
85 : 1000 : g_assert (g_type_is_a (liststore, liststore_interfaces[4]));
86 : 1000 : g_assert (!g_type_is_a (liststore, liststore_interfaces[5]));
87 : : }
88 : 1 : }
89 : :
90 : : static gpointer
91 : 2 : liststore_get_class (void)
92 : : {
93 : 2 : register_types ();
94 : 2 : return g_type_class_ref (liststore);
95 : : }
96 : :
97 : : static void
98 : 1 : liststore_interface_peek_run (gpointer klass)
99 : : {
100 : : guint i;
101 : : gpointer iface;
102 : :
103 : 1001 : for (i = 0; i < 1000; i++)
104 : : {
105 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[0]);
106 : 1000 : g_assert (iface);
107 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[1]);
108 : 1000 : g_assert (iface);
109 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[2]);
110 : 1000 : g_assert (iface);
111 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[3]);
112 : 1000 : g_assert (iface);
113 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[4]);
114 : 1000 : g_assert (iface);
115 : : }
116 : 1 : }
117 : :
118 : : static void
119 : 1 : liststore_interface_peek_same_run (gpointer klass)
120 : : {
121 : : guint i;
122 : : gpointer iface;
123 : :
124 : 1001 : for (i = 0; i < 1000; i++)
125 : : {
126 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[0]);
127 : 1000 : g_assert (iface);
128 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[0]);
129 : 1000 : g_assert (iface);
130 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[0]);
131 : 1000 : g_assert (iface);
132 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[0]);
133 : 1000 : g_assert (iface);
134 : 1000 : iface = g_type_interface_peek (klass, liststore_interfaces[0]);
135 : 1000 : g_assert (iface);
136 : : }
137 : 1 : }
138 : :
139 : : #if 0
140 : : /* DUMB test doing nothing */
141 : :
142 : : static gpointer
143 : : no_setup (void)
144 : : {
145 : : return NULL;
146 : : }
147 : :
148 : : static void
149 : : no_run (gpointer data)
150 : : {
151 : : }
152 : : #endif
153 : :
154 : : static void
155 : 3 : no_reset (gpointer data)
156 : : {
157 : 3 : }
158 : :
159 : : static void
160 : 1 : no_teardown (gpointer data)
161 : : {
162 : 1 : }
163 : :
164 : : typedef struct _PerformanceTest PerformanceTest;
165 : : struct _PerformanceTest {
166 : : const char *name;
167 : :
168 : : gpointer (*setup) (void);
169 : : void (*run) (gpointer data);
170 : : void (*reset) (gpointer data);
171 : : void (*teardown) (gpointer data);
172 : : };
173 : :
174 : : static const PerformanceTest tests[] = {
175 : : { "liststore-is-a",
176 : : register_types,
177 : : liststore_is_a_run,
178 : : no_reset,
179 : : no_teardown },
180 : : { "liststore-interface-peek",
181 : : liststore_get_class,
182 : : liststore_interface_peek_run,
183 : : no_reset,
184 : : g_type_class_unref },
185 : : { "liststore-interface-peek-same",
186 : : liststore_get_class,
187 : : liststore_interface_peek_same_run,
188 : : no_reset,
189 : : g_type_class_unref },
190 : : #if 0
191 : : { "nothing",
192 : : no_setup,
193 : : no_run,
194 : : no_reset,
195 : : no_teardown }
196 : : #endif
197 : : };
198 : :
199 : : static gboolean verbose = FALSE;
200 : : static guint n_threads = 0;
201 : : static gboolean list = FALSE;
202 : : static int test_length = DEFAULT_TEST_TIME;
203 : :
204 : : static GOptionEntry cmd_entries[] = {
205 : : {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
206 : : "Print extra information", NULL},
207 : : {"threads", 't', 0, G_OPTION_ARG_INT, &n_threads,
208 : : "number of threads to run in parallel", NULL},
209 : : {"seconds", 's', 0, G_OPTION_ARG_INT, &test_length,
210 : : "Time to run each test in seconds", NULL},
211 : : {"list", 'l', 0, G_OPTION_ARG_NONE, &list,
212 : : "List all available tests and exit", NULL},
213 : : G_OPTION_ENTRY_NULL
214 : : };
215 : :
216 : : static gpointer
217 : 3 : run_test_thread (gpointer user_data)
218 : : {
219 : 3 : const PerformanceTest *test = user_data;
220 : : gpointer data;
221 : : double elapsed;
222 : : GTimer *timer, *total;
223 : : GArray *results;
224 : :
225 : 3 : total = g_timer_new ();
226 : 3 : g_timer_start (total);
227 : :
228 : : /* Set up test */
229 : 3 : timer = g_timer_new ();
230 : 3 : data = test->setup ();
231 : 3 : results = g_array_new (FALSE, FALSE, sizeof (double));
232 : :
233 : : /* Run the test */
234 : : do
235 : : {
236 : 3 : g_timer_reset (timer);
237 : 3 : g_timer_start (timer);
238 : 3 : test->run (data);
239 : 3 : g_timer_stop (timer);
240 : 3 : elapsed = g_timer_elapsed (timer, NULL);
241 : 3 : g_array_append_val (results, elapsed);
242 : 3 : test->reset (data);
243 : : }
244 : 3 : while (g_timer_elapsed (total, NULL) < test_length);
245 : :
246 : : /* Tear down */
247 : 3 : test->teardown (data);
248 : 3 : g_timer_destroy (timer);
249 : 3 : g_timer_destroy (total);
250 : :
251 : 3 : return results;
252 : : }
253 : :
254 : : static int
255 : 0 : compare_doubles (gconstpointer a, gconstpointer b)
256 : : {
257 : 0 : double d = *(double *) a - *(double *) b;
258 : :
259 : 0 : if (d < 0)
260 : 0 : return -1;
261 : 0 : if (d > 0)
262 : 0 : return 1;
263 : 0 : return 0;
264 : : }
265 : :
266 : : static void
267 : 3 : print_results (GArray *array)
268 : : {
269 : : double min, max, avg;
270 : : guint i;
271 : :
272 : 3 : g_array_sort (array, compare_doubles);
273 : :
274 : : /* FIXME: discard outliers */
275 : :
276 : 3 : min = g_array_index (array, double, 0) * 1000;
277 : 3 : max = g_array_index (array, double, array->len - 1) * 1000;
278 : 3 : avg = 0;
279 : 6 : for (i = 0; i < array->len; i++)
280 : : {
281 : 3 : avg += g_array_index (array, double, i);
282 : : }
283 : 3 : avg = avg / array->len * 1000;
284 : :
285 : 3 : g_print (" %u runs, min/avg/max = %.3f/%.3f/%.3f ms\n", array->len, min, avg, max);
286 : 3 : }
287 : :
288 : : static void
289 : 3 : run_test (const PerformanceTest *test)
290 : : {
291 : : GArray *results;
292 : :
293 : 3 : g_print ("Running test \"%s\"\n", test->name);
294 : :
295 : 3 : if (n_threads == 0) {
296 : 3 : results = run_test_thread ((gpointer) test);
297 : : } else {
298 : : guint i;
299 : : GThread **threads;
300 : : GArray *thread_results;
301 : :
302 : 0 : threads = g_new (GThread *, n_threads);
303 : 0 : for (i = 0; i < n_threads; i++) {
304 : 0 : threads[i] = g_thread_new (NULL, run_test_thread, (gpointer) test);
305 : 0 : g_assert (threads[i] != NULL);
306 : : }
307 : :
308 : 0 : results = g_array_new (FALSE, FALSE, sizeof (double));
309 : 0 : for (i = 0; i < n_threads; i++) {
310 : 0 : thread_results = g_thread_join (threads[i]);
311 : 0 : g_array_append_vals (results, thread_results->data, thread_results->len);
312 : 0 : g_array_free (thread_results, TRUE);
313 : : }
314 : 0 : g_free (threads);
315 : : }
316 : :
317 : 3 : print_results (results);
318 : 3 : g_array_free (results, TRUE);
319 : 3 : }
320 : :
321 : : static const PerformanceTest *
322 : 0 : find_test (const char *name)
323 : : {
324 : : gsize i;
325 : 0 : for (i = 0; i < G_N_ELEMENTS (tests); i++)
326 : : {
327 : 0 : if (strcmp (tests[i].name, name) == 0)
328 : 0 : return &tests[i];
329 : : }
330 : 0 : return NULL;
331 : : }
332 : :
333 : : int
334 : 1 : main (int argc,
335 : : char *argv[])
336 : : {
337 : : const PerformanceTest *test;
338 : : GOptionContext *context;
339 : 1 : GError *error = NULL;
340 : : gsize i;
341 : :
342 : 1 : context = g_option_context_new ("GObject performance tests");
343 : 1 : g_option_context_add_main_entries (context, cmd_entries, NULL);
344 : 1 : if (!g_option_context_parse (context, &argc, &argv, &error))
345 : : {
346 : 0 : g_printerr ("%s: %s\n", argv[0], error->message);
347 : 0 : return 1;
348 : : }
349 : :
350 : 1 : if (list)
351 : : {
352 : 0 : for (i = 0; i < G_N_ELEMENTS (tests); i++)
353 : : {
354 : 0 : g_print ("%s\n", tests[i].name);
355 : : }
356 : 0 : return 0;
357 : : }
358 : :
359 : 1 : if (argc > 1)
360 : : {
361 : : int k;
362 : 0 : for (k = 1; k < argc; k++)
363 : : {
364 : 0 : test = find_test (argv[k]);
365 : 0 : if (test)
366 : 0 : run_test (test);
367 : : }
368 : : }
369 : : else
370 : : {
371 : 4 : for (i = 0; i < G_N_ELEMENTS (tests); i++)
372 : 3 : run_test (&tests[i]);
373 : : }
374 : :
375 : 1 : g_option_context_free (context);
376 : 1 : return 0;
377 : : }
|