053538f27ae7615058ba2b67be73bf3d4b315bc3
[platform/upstream/glib.git] / tests / gobject / performance.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 WARM_UP_N_RUNS 50
26 #define ESTIMATE_ROUND_TIME_N_RUNS 5
27 #define DEFAULT_TEST_TIME 15 /* seconds */
28  /* The time we want each round to take, in seconds, this should
29   * be large enough compared to the timer resolution, but small
30   * enought that the risk of any random slowness will miss the
31   * running window */
32 #define TARGET_ROUND_TIME 0.004
33
34 static gboolean verbose = FALSE;
35 static int test_length = DEFAULT_TEST_TIME;
36
37 static GOptionEntry cmd_entries[] = {
38   {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
39    "Print extra information", NULL},
40   {"seconds", 's', 0, G_OPTION_ARG_INT, &test_length,
41    "Time to run each test in seconds", NULL},
42   {NULL}
43 };
44
45 typedef struct _PerformanceTest PerformanceTest;
46 struct _PerformanceTest {
47   const char *name;
48   gpointer extra_data;
49
50   gpointer (*setup) (PerformanceTest *test);
51   void (*init) (PerformanceTest *test,
52                 gpointer data,
53                 double factor);
54   void (*run) (PerformanceTest *test,
55                gpointer data);
56   void (*finish) (PerformanceTest *test,
57                   gpointer data);
58   void (*teardown) (PerformanceTest *test,
59                     gpointer data);
60   void (*print_result) (PerformanceTest *test,
61                         gpointer data,
62                         double time);
63 };
64
65 static void
66 run_test (PerformanceTest *test)
67 {
68   gpointer data = NULL;
69   guint64 i, num_rounds;
70   double elapsed, min_elapsed, factor;
71   GTimer *timer;
72
73   g_print ("Running test %s\n", test->name);
74
75   /* Set up test */
76   timer = g_timer_new ();
77   data = test->setup (test);
78
79   if (verbose)
80     g_print ("Warming up\n");
81
82   /* Warm up the test by doing a few runs */
83   for (i = 0; i < WARM_UP_N_RUNS; i++)
84     {
85       test->init (test, data, 1.0);
86       test->run (test, data);
87       test->finish (test, data);
88     }
89
90   if (verbose)
91     g_print ("Estimating round time\n");
92
93   /* Estimate time for one run by doing a few test rounds */
94   min_elapsed = 0;
95   for (i = 0; i < ESTIMATE_ROUND_TIME_N_RUNS; i++)
96     {
97       test->init (test, data, 1.0);
98       g_timer_start (timer);
99       test->run (test, data);
100       g_timer_stop (timer);
101       test->finish (test, data);
102
103       elapsed = g_timer_elapsed (timer, NULL);
104       if (i == 0)
105         min_elapsed = elapsed;
106       else
107         min_elapsed = MIN (min_elapsed, elapsed);
108     }
109
110   factor = TARGET_ROUND_TIME / min_elapsed;
111
112   if (verbose)
113     g_print ("Uncorrected round time: %f.4 secs, correction factor %f.2\n", min_elapsed, factor);
114
115   /* Calculate number of rounds needed */
116   num_rounds = (test_length / TARGET_ROUND_TIME) + 1;
117
118   if (verbose)
119     g_print ("Running %"G_GINT64_MODIFIER"d rounds\n", num_rounds);
120
121   /* Run the test */
122   for (i = 0; i < num_rounds; i++)
123     {
124       test->init (test, data, factor);
125       g_timer_start (timer);
126       test->run (test, data);
127       g_timer_stop (timer);
128       test->finish (test, data);
129       elapsed = g_timer_elapsed (timer, NULL);
130
131       if (i == 0)
132         min_elapsed = elapsed;
133       else
134         min_elapsed = MIN (min_elapsed, elapsed);
135     }
136
137   if (verbose)
138     g_print ("Minimum corrected round time: %f secs\n", min_elapsed);
139
140   /* Print the results */
141   test->print_result (test, data, min_elapsed);
142
143   /* Tear down */
144   test->teardown (test, data);
145   g_timer_destroy (timer);
146 }
147
148 /*************************************************************
149  * Simple object is a very simple small GObject subclass
150  * with no properties, no signals, implementing no interfaces
151  *************************************************************/
152
153 static GType simple_object_get_type (void);
154 #define SIMPLE_TYPE_OBJECT        (simple_object_get_type ())
155 typedef struct _SimpleObject      SimpleObject;
156 typedef struct _SimpleObjectClass   SimpleObjectClass;
157
158 struct _SimpleObject
159 {
160   GObject parent_instance;
161   int val;
162 };
163
164 struct _SimpleObjectClass
165 {
166   GObjectClass parent_class;
167 };
168
169 G_DEFINE_TYPE (SimpleObject, simple_object, G_TYPE_OBJECT);
170
171 static void
172 simple_object_finalize (GObject *object)
173 {
174   G_OBJECT_CLASS (simple_object_parent_class)->finalize (object);
175 }
176
177 static void
178 simple_object_class_init (SimpleObjectClass *class)
179 {
180   GObjectClass *object_class = G_OBJECT_CLASS (class);
181
182   object_class->finalize = simple_object_finalize;
183 }
184
185 static void
186 simple_object_init (SimpleObject *simple_object)
187 {
188   simple_object->val = 42;
189 }
190
191 typedef struct _TestIfaceClass TestIfaceClass;
192 typedef struct _TestIfaceClass TestIface1Class;
193 typedef struct _TestIfaceClass TestIface2Class;
194 typedef struct _TestIfaceClass TestIface3Class;
195 typedef struct _TestIfaceClass TestIface4Class;
196 typedef struct _TestIfaceClass TestIface5Class;
197 typedef struct _TestIface TestIface;
198
199 struct _TestIfaceClass
200 {
201   GTypeInterface base_iface;
202   void (*method) (TestIface *obj);
203 };
204
205 static GType test_iface1_get_type (void);
206 static GType test_iface2_get_type (void);
207 static GType test_iface3_get_type (void);
208 static GType test_iface4_get_type (void);
209 static GType test_iface5_get_type (void);
210
211 #define TEST_TYPE_IFACE1 (test_iface1_get_type ())
212 #define TEST_TYPE_IFACE2 (test_iface2_get_type ())
213 #define TEST_TYPE_IFACE3 (test_iface3_get_type ())
214 #define TEST_TYPE_IFACE4 (test_iface4_get_type ())
215 #define TEST_TYPE_IFACE5 (test_iface5_get_type ())
216
217 static DEFINE_IFACE (TestIface1, test_iface1,  NULL, NULL)
218 static DEFINE_IFACE (TestIface2, test_iface2,  NULL, NULL)
219 static DEFINE_IFACE (TestIface3, test_iface3,  NULL, NULL)
220 static DEFINE_IFACE (TestIface4, test_iface4,  NULL, NULL)
221 static DEFINE_IFACE (TestIface5, test_iface5,  NULL, NULL)
222
223 /*************************************************************
224  * Complex object is a GObject subclass with a properties,
225  * construct properties, signals and implementing an interface.
226  *************************************************************/
227
228 static GType complex_object_get_type (void);
229 #define COMPLEX_TYPE_OBJECT        (complex_object_get_type ())
230 typedef struct _ComplexObject      ComplexObject;
231 typedef struct _ComplexObjectClass ComplexObjectClass;
232
233 struct _ComplexObject
234 {
235   GObject parent_instance;
236   int val1;
237   int val2;
238 };
239
240 struct _ComplexObjectClass
241 {
242   GObjectClass parent_class;
243
244   void (*signal) (ComplexObject *obj);
245   void (*signal_empty) (ComplexObject *obj);
246 };
247
248 static void complex_test_iface_init (gpointer         g_iface,
249                                      gpointer         iface_data);
250
251 G_DEFINE_TYPE_EXTENDED (ComplexObject, complex_object,
252                         G_TYPE_OBJECT, 0,
253                         G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE1,
254                                                complex_test_iface_init)
255                         G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE2,
256                                                complex_test_iface_init)
257                         G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE3,
258                                                complex_test_iface_init)
259                         G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE4,
260                                                complex_test_iface_init)
261                         G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE5,
262                                                complex_test_iface_init)
263                         );
264
265 #define COMPLEX_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), COMPLEX_TYPE_OBJECT, ComplexObject))
266
267 enum {
268   PROP_0,
269   PROP_VAL1,
270   PROP_VAL2
271 };
272
273 enum {
274   COMPLEX_SIGNAL,
275   COMPLEX_SIGNAL_EMPTY,
276   COMPLEX_SIGNAL_GENERIC,
277   COMPLEX_SIGNAL_GENERIC_EMPTY,
278   COMPLEX_LAST_SIGNAL
279 };
280
281 static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
282
283 static void
284 complex_object_finalize (GObject *object)
285 {
286   G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
287 }
288
289 static void
290 complex_object_set_property (GObject         *object,
291                              guint            prop_id,
292                              const GValue    *value,
293                              GParamSpec      *pspec)
294 {
295   ComplexObject *complex = COMPLEX_OBJECT (object);
296
297   switch (prop_id)
298     {
299     case PROP_VAL1:
300       complex->val1 = g_value_get_int (value);
301       break;
302     case PROP_VAL2:
303       complex->val2 = g_value_get_int (value);
304       break;
305     default:
306       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
307       break;
308     }
309 }
310
311 static void
312 complex_object_get_property (GObject         *object,
313                              guint            prop_id,
314                              GValue          *value,
315                              GParamSpec      *pspec)
316 {
317   ComplexObject *complex = COMPLEX_OBJECT (object);
318
319   switch (prop_id)
320     {
321     case PROP_VAL1:
322       g_value_set_int (value, complex->val1);
323       break;
324     case PROP_VAL2:
325       g_value_set_int (value, complex->val2);
326       break;
327     default:
328       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
329       break;
330     }
331 }
332
333 static void
334 complex_object_real_signal (ComplexObject *obj)
335 {
336 }
337
338 static void
339 complex_object_class_init (ComplexObjectClass *class)
340 {
341   GObjectClass *object_class = G_OBJECT_CLASS (class);
342
343   object_class->finalize = complex_object_finalize;
344   object_class->set_property = complex_object_set_property;
345   object_class->get_property = complex_object_get_property;
346
347   class->signal = complex_object_real_signal;
348
349   complex_signals[COMPLEX_SIGNAL] =
350     g_signal_new ("signal",
351                   G_TYPE_FROM_CLASS (object_class),
352                   G_SIGNAL_RUN_FIRST,
353                   G_STRUCT_OFFSET (ComplexObjectClass, signal),
354                   NULL, NULL,
355                   g_cclosure_marshal_VOID__VOID,
356                   G_TYPE_NONE, 0);
357
358   complex_signals[COMPLEX_SIGNAL_EMPTY] =
359     g_signal_new ("signal-empty",
360                   G_TYPE_FROM_CLASS (object_class),
361                   G_SIGNAL_RUN_FIRST,
362                   G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
363                   NULL, NULL,
364                   g_cclosure_marshal_VOID__VOID,
365                   G_TYPE_NONE, 0);
366
367   complex_signals[COMPLEX_SIGNAL_GENERIC] =
368     g_signal_new ("signal-generic",
369                   G_TYPE_FROM_CLASS (object_class),
370                   G_SIGNAL_RUN_FIRST,
371                   G_STRUCT_OFFSET (ComplexObjectClass, signal),
372                   NULL, NULL,
373                   NULL,
374                   G_TYPE_NONE, 0);
375   complex_signals[COMPLEX_SIGNAL_GENERIC_EMPTY] =
376     g_signal_new ("signal-generic-empty",
377                   G_TYPE_FROM_CLASS (object_class),
378                   G_SIGNAL_RUN_FIRST,
379                   G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
380                   NULL, NULL,
381                   NULL,
382                   G_TYPE_NONE, 0);
383
384   g_object_class_install_property (object_class,
385                                    PROP_VAL1,
386                                    g_param_spec_int ("val1",
387                                                      "val1",
388                                                      "val1",
389                                                      0,
390                                                      G_MAXINT,
391                                                      42,
392                                                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
393   g_object_class_install_property (object_class,
394                                    PROP_VAL2,
395                                    g_param_spec_int ("val2",
396                                                      "val2",
397                                                      "val2",
398                                                      0,
399                                                      G_MAXINT,
400                                                      43,
401                                                      G_PARAM_READWRITE));
402
403
404 }
405
406 static void
407 complex_object_iface_method (TestIface *obj)
408 {
409   ComplexObject *complex = COMPLEX_OBJECT (obj);
410   complex->val1++;
411 }
412
413 static void
414 complex_test_iface_init (gpointer         g_iface,
415                          gpointer         iface_data)
416 {
417   TestIfaceClass *iface = g_iface;
418   iface->method = complex_object_iface_method;
419 }
420
421 static void
422 complex_object_init (ComplexObject *complex_object)
423 {
424   complex_object->val2 = 43;
425 }
426
427 /*************************************************************
428  * Test object construction performance
429  *************************************************************/
430
431 #define NUM_OBJECT_TO_CONSTRUCT 10000
432
433 struct ConstructionTest {
434   GObject **objects;
435   int n_objects;
436   GType type;
437 };
438
439 static gpointer
440 test_construction_setup (PerformanceTest *test)
441 {
442   struct ConstructionTest *data;
443
444   data = g_new0 (struct ConstructionTest, 1);
445   data->type = ((GType (*)())test->extra_data)();
446
447   return data;
448 }
449
450 static void
451 test_construction_init (PerformanceTest *test,
452                         gpointer _data,
453                         double count_factor)
454 {
455   struct ConstructionTest *data = _data;
456   int n;
457
458   n = NUM_OBJECT_TO_CONSTRUCT * count_factor;
459   if (data->n_objects != n)
460     {
461       data->n_objects = n;
462       data->objects = g_new (GObject *, n);
463     }
464 }
465
466 static void
467 test_construction_run (PerformanceTest *test,
468                        gpointer _data)
469 {
470   struct ConstructionTest *data = _data;
471   GObject **objects = data->objects;
472   GType type = data->type;
473   int i, n_objects;
474
475   n_objects = data->n_objects;
476   for (i = 0; i < n_objects; i++)
477     objects[i] = g_object_new (type, NULL);
478 }
479
480 static void
481 test_construction_finish (PerformanceTest *test,
482                           gpointer _data)
483 {
484   struct ConstructionTest *data = _data;
485   int i;
486
487   for (i = 0; i < data->n_objects; i++)
488     g_object_unref (data->objects[i]);
489 }
490
491 static void
492 test_construction_teardown (PerformanceTest *test,
493                             gpointer _data)
494 {
495   struct ConstructionTest *data = _data;
496   g_free (data->objects);
497   g_free (data);
498 }
499
500 static void
501 test_construction_print_result (PerformanceTest *test,
502                                 gpointer _data,
503                                 double time)
504 {
505   struct ConstructionTest *data = _data;
506
507   g_print ("Number of constructed objects per second: %.0f\n",
508            data->n_objects / time);
509 }
510
511 /*************************************************************
512  * Test runtime type check performance
513  *************************************************************/
514
515 #define NUM_KILO_CHECKS_PER_ROUND 50
516
517 struct TypeCheckTest {
518   GObject *object;
519   int n_checks;
520 };
521
522 static gpointer
523 test_type_check_setup (PerformanceTest *test)
524 {
525   struct TypeCheckTest *data;
526
527   data = g_new0 (struct TypeCheckTest, 1);
528   data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
529
530   return data;
531 }
532
533 static void
534 test_type_check_init (PerformanceTest *test,
535                       gpointer _data,
536                       double factor)
537 {
538   struct TypeCheckTest *data = _data;
539
540   data->n_checks = factor * NUM_KILO_CHECKS_PER_ROUND;
541 }
542
543
544 /* Work around g_type_check_instance_is_a being marked "pure",
545    and thus only called once for the loop. */
546 gboolean (*my_type_check_instance_is_a) (GTypeInstance *type_instance,
547                                          GType          iface_type) = &g_type_check_instance_is_a;
548
549 static void
550 test_type_check_run (PerformanceTest *test,
551                      gpointer _data)
552 {
553   struct TypeCheckTest *data = _data;
554   volatile GObject *object = data->object;
555   volatile GType type, types[5];
556   int i, j;
557
558   types[0] = test_iface1_get_type ();
559   types[1] = test_iface2_get_type ();
560   types[2] = test_iface3_get_type ();
561   types[3] = test_iface4_get_type ();
562   types[4] = test_iface5_get_type ();
563
564   for (i = 0; i < data->n_checks; i++)
565     {
566       type = types[i%5];
567       for (j = 0; j < 1000; j++)
568         {
569           my_type_check_instance_is_a ((GTypeInstance *)object,
570                                        type);
571         }
572     }
573 }
574
575 static void
576 test_type_check_finish (PerformanceTest *test,
577                         gpointer data)
578 {
579 }
580
581 static void
582 test_type_check_print_result (PerformanceTest *test,
583                               gpointer _data,
584                               double time)
585 {
586   struct TypeCheckTest *data = _data;
587   g_print ("Million type checks per second: %.2f\n",
588            data->n_checks / (1000*time));
589 }
590
591 static void
592 test_type_check_teardown (PerformanceTest *test,
593                           gpointer _data)
594 {
595   struct TypeCheckTest *data = _data;
596
597   g_object_unref (data->object);
598   g_free (data);
599 }
600
601 /*************************************************************
602  * Test signal unhandled emissions performance
603  *************************************************************/
604
605 #define NUM_EMISSIONS_PER_ROUND 10000
606
607 struct EmissionTest {
608   GObject *object;
609   int n_checks;
610   int signal_id;
611 };
612
613 static gpointer
614 test_emission_unhandled_setup (PerformanceTest *test)
615 {
616   struct EmissionTest *data;
617
618   data = g_new0 (struct EmissionTest, 1);
619   data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
620   data->signal_id = complex_signals[GPOINTER_TO_INT (test->extra_data)];
621   return data;
622 }
623
624 static void
625 test_emission_unhandled_init (PerformanceTest *test,
626                               gpointer _data,
627                               double factor)
628 {
629   struct EmissionTest *data = _data;
630
631   data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
632 }
633
634 static void
635 test_emission_unhandled_run (PerformanceTest *test,
636                              gpointer _data)
637 {
638   struct EmissionTest *data = _data;
639   GObject *object = data->object;
640   int i;
641
642   for (i = 0; i < data->n_checks; i++)
643     g_signal_emit (object,
644                    data->signal_id,
645                    0);
646 }
647
648 static void
649 test_emission_unhandled_finish (PerformanceTest *test,
650                                 gpointer data)
651 {
652 }
653
654 static void
655 test_emission_unhandled_print_result (PerformanceTest *test,
656                                       gpointer _data,
657                                       double time)
658 {
659   struct EmissionTest *data = _data;
660
661   g_print ("Emissions per second: %.0f\n",
662            data->n_checks / time);
663 }
664
665 static void
666 test_emission_unhandled_teardown (PerformanceTest *test,
667                                   gpointer _data)
668 {
669   struct EmissionTest *data = _data;
670
671   g_object_unref (data->object);
672   g_free (data);
673 }
674
675 /*************************************************************
676  * Test signal handled emissions performance
677  *************************************************************/
678
679 static void
680 test_emission_handled_handler (ComplexObject *obj, gpointer data)
681 {
682 }
683
684 static gpointer
685 test_emission_handled_setup (PerformanceTest *test)
686 {
687   struct EmissionTest *data;
688
689   data = g_new0 (struct EmissionTest, 1);
690   data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
691   data->signal_id = complex_signals[GPOINTER_TO_INT (test->extra_data)];
692   g_signal_connect (data->object, "signal",
693                     G_CALLBACK (test_emission_handled_handler),
694                     NULL);
695   g_signal_connect (data->object, "signal-empty",
696                     G_CALLBACK (test_emission_handled_handler),
697                     NULL);
698   g_signal_connect (data->object, "signal-generic",
699                     G_CALLBACK (test_emission_handled_handler),
700                     NULL);
701   g_signal_connect (data->object, "signal-generic-empty",
702                     G_CALLBACK (test_emission_handled_handler),
703                     NULL);
704
705   return data;
706 }
707
708 static void
709 test_emission_handled_init (PerformanceTest *test,
710                             gpointer _data,
711                             double factor)
712 {
713   struct EmissionTest *data = _data;
714
715   data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
716 }
717
718 static void
719 test_emission_handled_run (PerformanceTest *test,
720                            gpointer _data)
721 {
722   struct EmissionTest *data = _data;
723   GObject *object = data->object;
724   int i;
725
726   for (i = 0; i < data->n_checks; i++)
727     g_signal_emit (object,
728                    data->signal_id,
729                    0);
730 }
731
732 static void
733 test_emission_handled_finish (PerformanceTest *test,
734                               gpointer data)
735 {
736 }
737
738 static void
739 test_emission_handled_print_result (PerformanceTest *test,
740                                     gpointer _data,
741                                     double time)
742 {
743   struct EmissionTest *data = _data;
744
745   g_print ("Emissions per second: %.0f\n",
746            data->n_checks / time);
747 }
748
749 static void
750 test_emission_handled_teardown (PerformanceTest *test,
751                                 gpointer _data)
752 {
753   struct EmissionTest *data = _data;
754
755   g_object_unref (data->object);
756   g_free (data);
757 }
758
759 /*************************************************************
760  * Main test code
761  *************************************************************/
762
763 static PerformanceTest tests[] = {
764   {
765     "simple-construction",
766     simple_object_get_type,
767     test_construction_setup,
768     test_construction_init,
769     test_construction_run,
770     test_construction_finish,
771     test_construction_teardown,
772     test_construction_print_result
773   },
774   {
775     "complex-construction",
776     complex_object_get_type,
777     test_construction_setup,
778     test_construction_init,
779     test_construction_run,
780     test_construction_finish,
781     test_construction_teardown,
782     test_construction_print_result
783   },
784   {
785     "type-check",
786     NULL,
787     test_type_check_setup,
788     test_type_check_init,
789     test_type_check_run,
790     test_type_check_finish,
791     test_type_check_teardown,
792     test_type_check_print_result
793   },
794   {
795     "emit-unhandled",
796     GINT_TO_POINTER (COMPLEX_SIGNAL),
797     test_emission_unhandled_setup,
798     test_emission_unhandled_init,
799     test_emission_unhandled_run,
800     test_emission_unhandled_finish,
801     test_emission_unhandled_teardown,
802     test_emission_unhandled_print_result
803   },
804   {
805     "emit-unhandled-empty",
806     GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
807     test_emission_unhandled_setup,
808     test_emission_unhandled_init,
809     test_emission_unhandled_run,
810     test_emission_unhandled_finish,
811     test_emission_unhandled_teardown,
812     test_emission_unhandled_print_result
813   },
814   {
815     "emit-unhandled-generic",
816     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
817     test_emission_unhandled_setup,
818     test_emission_unhandled_init,
819     test_emission_unhandled_run,
820     test_emission_unhandled_finish,
821     test_emission_unhandled_teardown,
822     test_emission_unhandled_print_result
823   },
824   {
825     "emit-unhandled-generic-empty",
826     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
827     test_emission_unhandled_setup,
828     test_emission_unhandled_init,
829     test_emission_unhandled_run,
830     test_emission_unhandled_finish,
831     test_emission_unhandled_teardown,
832     test_emission_unhandled_print_result
833   },
834   {
835     "emit-handled",
836     GINT_TO_POINTER (COMPLEX_SIGNAL),
837     test_emission_handled_setup,
838     test_emission_handled_init,
839     test_emission_handled_run,
840     test_emission_handled_finish,
841     test_emission_handled_teardown,
842     test_emission_handled_print_result
843   },
844   {
845     "emit-handled-empty",
846     GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
847     test_emission_handled_setup,
848     test_emission_handled_init,
849     test_emission_handled_run,
850     test_emission_handled_finish,
851     test_emission_handled_teardown,
852     test_emission_handled_print_result
853   },
854   {
855     "emit-handled-generic",
856     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
857     test_emission_handled_setup,
858     test_emission_handled_init,
859     test_emission_handled_run,
860     test_emission_handled_finish,
861     test_emission_handled_teardown,
862     test_emission_handled_print_result
863   },
864   {
865     "emit-handled-generic-empty",
866     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
867     test_emission_handled_setup,
868     test_emission_handled_init,
869     test_emission_handled_run,
870     test_emission_handled_finish,
871     test_emission_handled_teardown,
872     test_emission_handled_print_result
873   }
874 };
875
876 static PerformanceTest *
877 find_test (const char *name)
878 {
879   int i;
880   for (i = 0; i < G_N_ELEMENTS (tests); i++)
881     {
882       if (strcmp (tests[i].name, name) == 0)
883         return &tests[i];
884     }
885   return NULL;
886 }
887 int
888 main (int   argc,
889       char *argv[])
890 {
891   PerformanceTest *test;
892   GOptionContext *context;
893   GError *error = NULL;
894   int i;
895
896   context = g_option_context_new ("GObject performance tests");
897   g_option_context_add_main_entries (context, cmd_entries, NULL);
898   if (!g_option_context_parse (context, &argc, &argv, &error))
899     {
900       g_printerr ("%s: %s\n", argv[0], error->message);
901       return 1;
902     }
903
904   if (argc > 1)
905     {
906       for (i = 1; i < argc; i++)
907         {
908           test = find_test (argv[i]);
909           if (test)
910             run_test (test);
911         }
912     }
913   else
914     {
915       for (i = 0; i < G_N_ELEMENTS (tests); i++)
916         run_test (&tests[i]);
917     }
918
919   return 0;
920 }