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