[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[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, 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 simple_register_class (const char *name, GType parent, ...)
27 {
28   GInterfaceInfo interface_info = { NULL, NULL, NULL };
29   va_list args;
30   GType type, interface;
31
32   va_start (args, parent);
33   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       interface = va_arg (args, GType);
38       if (interface == 0)
39         break;
40       g_type_add_interface_static (type, interface, &interface_info);
41     }
42   va_end (args);
43
44   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 register_types (void)
54 {
55   static volatile gsize inited = 0;
56   if (g_once_init_enter (&inited))
57     {
58       liststore_interfaces[0] = simple_register_class ("GtkBuildable", G_TYPE_INTERFACE, 0);
59       liststore_interfaces[1] = simple_register_class ("GtkTreeDragDest", G_TYPE_INTERFACE, 0);
60       liststore_interfaces[2] = simple_register_class ("GtkTreeModel", G_TYPE_INTERFACE, 0);
61       liststore_interfaces[3] = simple_register_class ("GtkTreeDragSource", G_TYPE_INTERFACE, 0);
62       liststore_interfaces[4] = simple_register_class ("GtkTreeSortable", G_TYPE_INTERFACE, 0);
63       liststore_interfaces[5] = simple_register_class ("UnrelatedInterface", G_TYPE_INTERFACE, 0);
64
65       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       g_once_init_leave (&inited, 1);
70     }
71   return NULL;
72 }
73
74 static void 
75 liststore_is_a_run (gpointer data)
76 {
77   guint i;
78
79   for (i = 0; i < 1000; i++)
80     {
81       g_assert (g_type_is_a (liststore, liststore_interfaces[0]));
82       g_assert (g_type_is_a (liststore, liststore_interfaces[1]));
83       g_assert (g_type_is_a (liststore, liststore_interfaces[2]));
84       g_assert (g_type_is_a (liststore, liststore_interfaces[3]));
85       g_assert (g_type_is_a (liststore, liststore_interfaces[4]));
86       g_assert (!g_type_is_a (liststore, liststore_interfaces[5]));
87     }
88 }
89
90 static gpointer
91 liststore_get_class (void)
92 {
93   register_types ();
94   return g_type_class_ref (liststore);
95 }
96
97 static void 
98 liststore_interface_peek_run (gpointer klass)
99 {
100   guint i;
101   gpointer iface;
102
103   for (i = 0; i < 1000; i++)
104     {
105       iface = g_type_interface_peek (klass, liststore_interfaces[0]);
106       g_assert (iface);
107       iface = g_type_interface_peek (klass, liststore_interfaces[1]);
108       g_assert (iface);
109       iface = g_type_interface_peek (klass, liststore_interfaces[2]);
110       g_assert (iface);
111       iface = g_type_interface_peek (klass, liststore_interfaces[3]);
112       g_assert (iface);
113       iface = g_type_interface_peek (klass, liststore_interfaces[4]);
114       g_assert (iface);
115     }
116 }
117
118 static void 
119 liststore_interface_peek_same_run (gpointer klass)
120 {
121   guint i;
122   gpointer iface;
123
124   for (i = 0; i < 1000; i++)
125     {
126       iface = g_type_interface_peek (klass, liststore_interfaces[0]);
127       g_assert (iface);
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     }
137 }
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 no_reset (gpointer data)
156 {
157 }
158
159 static void 
160 no_teardown (gpointer data)
161 {
162 }
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 int 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 parrallel", 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   {NULL}
214 };
215
216 static gpointer
217 run_test_thread (gpointer user_data)
218 {
219   const PerformanceTest *test = user_data;
220   gpointer data;
221   double elapsed;
222   GTimer *timer, *total;
223   GArray *results;
224
225   total = g_timer_new ();
226   g_timer_start (total);
227
228   /* Set up test */
229   timer = g_timer_new ();
230   data = test->setup ();
231   results = g_array_new (FALSE, FALSE, sizeof (double));
232
233   /* Run the test */
234   while (g_timer_elapsed (total, NULL) < test_length)
235     {
236       g_timer_reset (timer);
237       g_timer_start (timer);
238       test->run (data);
239       g_timer_stop (timer);
240       elapsed = g_timer_elapsed (timer, NULL);
241       g_array_append_val (results, elapsed);
242       test->reset (data);
243     }
244
245   /* Tear down */
246   test->teardown (data);
247   g_timer_destroy (timer);
248   g_timer_destroy (total);
249
250   return results;
251 }
252
253 static int
254 compare_doubles (gconstpointer a, gconstpointer b)
255 {
256   double d = *(double *) a - *(double *) b;
257
258   if (d < 0)
259     return -1;
260   if (d > 0)
261     return 1;
262   return 0;
263 }
264
265 static void
266 print_results (GArray *array)
267 {
268   double min, max, avg;
269   guint i;
270
271   g_array_sort (array, compare_doubles);
272
273   /* FIXME: discard outliers */
274
275   min = g_array_index (array, double, 0) * 1000;
276   max = g_array_index (array, double, array->len - 1) * 1000;
277   avg = 0;
278   for (i = 0; i < array->len; i++)
279     {
280       avg += g_array_index (array, double, i);
281     }
282   avg = avg / array->len * 1000;
283
284   g_print ("  %u runs, min/avg/max = %.3f/%.3f/%.3f ms\n", array->len, min, avg, max);
285 }
286
287 static void
288 run_test (const PerformanceTest *test)
289 {
290   GArray *results;
291
292   g_print ("Running test \"%s\"\n", test->name);
293
294   if (n_threads == 0) {
295     results = run_test_thread ((gpointer) test);
296   } else {
297     guint i;
298     GThread **threads;
299     GArray *thread_results;
300       
301     threads = g_new (GThread *, n_threads);
302     for (i = 0; i < n_threads; i++) {
303       threads[i] = g_thread_create (run_test_thread, (gpointer) test, TRUE, NULL);
304       g_assert (threads[i] != NULL);
305     }
306
307     results = g_array_new (FALSE, FALSE, sizeof (double));
308     for (i = 0; i < n_threads; i++) {
309       thread_results = g_thread_join (threads[i]);
310       g_array_append_vals (results, thread_results->data, thread_results->len);
311       g_array_free (thread_results, TRUE);
312     }
313     g_free (threads);
314   }
315
316   print_results (results);
317   g_array_free (results, TRUE);
318 }
319
320 static const PerformanceTest *
321 find_test (const char *name)
322 {
323   int i;
324   for (i = 0; i < G_N_ELEMENTS (tests); i++)
325     {
326       if (strcmp (tests[i].name, name) == 0)
327         return &tests[i];
328     }
329   return NULL;
330 }
331
332 int
333 main (int   argc,
334       char *argv[])
335 {
336   const PerformanceTest *test;
337   GOptionContext *context;
338   GError *error = NULL;
339   int i;
340
341   context = g_option_context_new ("GObject performance tests");
342   g_option_context_add_main_entries (context, cmd_entries, NULL);
343   if (!g_option_context_parse (context, &argc, &argv, &error))
344     {
345       g_printerr ("%s: %s\n", argv[0], error->message);
346       return 1;
347     }
348
349   if (list)
350     {
351       for (i = 0; i < G_N_ELEMENTS (tests); i++)
352         {
353           g_print ("%s\n", tests[i].name);
354         }
355       return 0;
356     }
357
358   if (argc > 1)
359     {
360       for (i = 1; i < argc; i++)
361         {
362           test = find_test (argv[i]);
363           if (test)
364             run_test (test);
365         }
366     }
367   else
368     {
369       for (i = 0; i < G_N_ELEMENTS (tests); i++)
370         run_test (&tests[i]);
371     }
372
373   return 0;
374 }