fdc51da28b360214a30b89a9597a2bce09d629f2
[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_SIGNAL_ARGS,
279   COMPLEX_LAST_SIGNAL
280 };
281
282 static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
283
284 static void
285 complex_object_finalize (GObject *object)
286 {
287   G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
288 }
289
290 static void
291 complex_object_set_property (GObject         *object,
292                              guint            prop_id,
293                              const GValue    *value,
294                              GParamSpec      *pspec)
295 {
296   ComplexObject *complex = COMPLEX_OBJECT (object);
297
298   switch (prop_id)
299     {
300     case PROP_VAL1:
301       complex->val1 = g_value_get_int (value);
302       break;
303     case PROP_VAL2:
304       complex->val2 = g_value_get_int (value);
305       break;
306     default:
307       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308       break;
309     }
310 }
311
312 static void
313 complex_object_get_property (GObject         *object,
314                              guint            prop_id,
315                              GValue          *value,
316                              GParamSpec      *pspec)
317 {
318   ComplexObject *complex = COMPLEX_OBJECT (object);
319
320   switch (prop_id)
321     {
322     case PROP_VAL1:
323       g_value_set_int (value, complex->val1);
324       break;
325     case PROP_VAL2:
326       g_value_set_int (value, complex->val2);
327       break;
328     default:
329       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
330       break;
331     }
332 }
333
334 static void
335 complex_object_real_signal (ComplexObject *obj)
336 {
337 }
338
339 static void
340 complex_object_class_init (ComplexObjectClass *class)
341 {
342   GObjectClass *object_class = G_OBJECT_CLASS (class);
343
344   object_class->finalize = complex_object_finalize;
345   object_class->set_property = complex_object_set_property;
346   object_class->get_property = complex_object_get_property;
347
348   class->signal = complex_object_real_signal;
349
350   complex_signals[COMPLEX_SIGNAL] =
351     g_signal_new ("signal",
352                   G_TYPE_FROM_CLASS (object_class),
353                   G_SIGNAL_RUN_FIRST,
354                   G_STRUCT_OFFSET (ComplexObjectClass, signal),
355                   NULL, NULL,
356                   g_cclosure_marshal_VOID__VOID,
357                   G_TYPE_NONE, 0);
358
359   complex_signals[COMPLEX_SIGNAL_EMPTY] =
360     g_signal_new ("signal-empty",
361                   G_TYPE_FROM_CLASS (object_class),
362                   G_SIGNAL_RUN_FIRST,
363                   G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
364                   NULL, NULL,
365                   g_cclosure_marshal_VOID__VOID,
366                   G_TYPE_NONE, 0);
367
368   complex_signals[COMPLEX_SIGNAL_GENERIC] =
369     g_signal_new ("signal-generic",
370                   G_TYPE_FROM_CLASS (object_class),
371                   G_SIGNAL_RUN_FIRST,
372                   G_STRUCT_OFFSET (ComplexObjectClass, signal),
373                   NULL, NULL,
374                   NULL,
375                   G_TYPE_NONE, 0);
376   complex_signals[COMPLEX_SIGNAL_GENERIC_EMPTY] =
377     g_signal_new ("signal-generic-empty",
378                   G_TYPE_FROM_CLASS (object_class),
379                   G_SIGNAL_RUN_FIRST,
380                   G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
381                   NULL, NULL,
382                   NULL,
383                   G_TYPE_NONE, 0);
384
385   complex_signals[COMPLEX_SIGNAL_ARGS] =
386     g_signal_new ("signal-args",
387                   G_TYPE_FROM_CLASS (object_class),
388                   G_SIGNAL_RUN_FIRST,
389                   G_STRUCT_OFFSET (ComplexObjectClass, signal),
390                   NULL, NULL,
391                   g_cclosure_marshal_VOID__UINT_POINTER,
392                   G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
393
394   g_object_class_install_property (object_class,
395                                    PROP_VAL1,
396                                    g_param_spec_int ("val1",
397                                                      "val1",
398                                                      "val1",
399                                                      0,
400                                                      G_MAXINT,
401                                                      42,
402                                                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
403   g_object_class_install_property (object_class,
404                                    PROP_VAL2,
405                                    g_param_spec_int ("val2",
406                                                      "val2",
407                                                      "val2",
408                                                      0,
409                                                      G_MAXINT,
410                                                      43,
411                                                      G_PARAM_READWRITE));
412
413
414 }
415
416 static void
417 complex_object_iface_method (TestIface *obj)
418 {
419   ComplexObject *complex = COMPLEX_OBJECT (obj);
420   complex->val1++;
421 }
422
423 static void
424 complex_test_iface_init (gpointer         g_iface,
425                          gpointer         iface_data)
426 {
427   TestIfaceClass *iface = g_iface;
428   iface->method = complex_object_iface_method;
429 }
430
431 static void
432 complex_object_init (ComplexObject *complex_object)
433 {
434   complex_object->val2 = 43;
435 }
436
437 /*************************************************************
438  * Test object construction performance
439  *************************************************************/
440
441 #define NUM_OBJECT_TO_CONSTRUCT 10000
442
443 struct ConstructionTest {
444   GObject **objects;
445   int n_objects;
446   GType type;
447 };
448
449 static gpointer
450 test_construction_setup (PerformanceTest *test)
451 {
452   struct ConstructionTest *data;
453
454   data = g_new0 (struct ConstructionTest, 1);
455   data->type = ((GType (*)(void))test->extra_data)();
456
457   return data;
458 }
459
460 static void
461 test_construction_init (PerformanceTest *test,
462                         gpointer _data,
463                         double count_factor)
464 {
465   struct ConstructionTest *data = _data;
466   int n;
467
468   n = NUM_OBJECT_TO_CONSTRUCT * count_factor;
469   if (data->n_objects != n)
470     {
471       data->n_objects = n;
472       data->objects = g_new (GObject *, n);
473     }
474 }
475
476 static void
477 test_construction_run (PerformanceTest *test,
478                        gpointer _data)
479 {
480   struct ConstructionTest *data = _data;
481   GObject **objects = data->objects;
482   GType type = data->type;
483   int i, n_objects;
484
485   n_objects = data->n_objects;
486   for (i = 0; i < n_objects; i++)
487     objects[i] = g_object_new (type, NULL);
488 }
489
490 static void
491 test_construction_finish (PerformanceTest *test,
492                           gpointer _data)
493 {
494   struct ConstructionTest *data = _data;
495   int i;
496
497   for (i = 0; i < data->n_objects; i++)
498     g_object_unref (data->objects[i]);
499 }
500
501 static void
502 test_construction_teardown (PerformanceTest *test,
503                             gpointer _data)
504 {
505   struct ConstructionTest *data = _data;
506   g_free (data->objects);
507   g_free (data);
508 }
509
510 static void
511 test_construction_print_result (PerformanceTest *test,
512                                 gpointer _data,
513                                 double time)
514 {
515   struct ConstructionTest *data = _data;
516
517   g_print ("Number of constructed objects per second: %.0f\n",
518            data->n_objects / time);
519 }
520
521 /*************************************************************
522  * Test runtime type check performance
523  *************************************************************/
524
525 #define NUM_KILO_CHECKS_PER_ROUND 50
526
527 struct TypeCheckTest {
528   GObject *object;
529   int n_checks;
530 };
531
532 static gpointer
533 test_type_check_setup (PerformanceTest *test)
534 {
535   struct TypeCheckTest *data;
536
537   data = g_new0 (struct TypeCheckTest, 1);
538   data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
539
540   return data;
541 }
542
543 static void
544 test_type_check_init (PerformanceTest *test,
545                       gpointer _data,
546                       double factor)
547 {
548   struct TypeCheckTest *data = _data;
549
550   data->n_checks = factor * NUM_KILO_CHECKS_PER_ROUND;
551 }
552
553
554 /* Work around g_type_check_instance_is_a being marked "pure",
555    and thus only called once for the loop. */
556 gboolean (*my_type_check_instance_is_a) (GTypeInstance *type_instance,
557                                          GType          iface_type) = &g_type_check_instance_is_a;
558
559 static void
560 test_type_check_run (PerformanceTest *test,
561                      gpointer _data)
562 {
563   struct TypeCheckTest *data = _data;
564   volatile GObject *object = data->object;
565   volatile GType type, types[5];
566   int i, j;
567
568   types[0] = test_iface1_get_type ();
569   types[1] = test_iface2_get_type ();
570   types[2] = test_iface3_get_type ();
571   types[3] = test_iface4_get_type ();
572   types[4] = test_iface5_get_type ();
573
574   for (i = 0; i < data->n_checks; i++)
575     {
576       type = types[i%5];
577       for (j = 0; j < 1000; j++)
578         {
579           my_type_check_instance_is_a ((GTypeInstance *)object,
580                                        type);
581         }
582     }
583 }
584
585 static void
586 test_type_check_finish (PerformanceTest *test,
587                         gpointer data)
588 {
589 }
590
591 static void
592 test_type_check_print_result (PerformanceTest *test,
593                               gpointer _data,
594                               double time)
595 {
596   struct TypeCheckTest *data = _data;
597   g_print ("Million type checks per second: %.2f\n",
598            data->n_checks / (1000*time));
599 }
600
601 static void
602 test_type_check_teardown (PerformanceTest *test,
603                           gpointer _data)
604 {
605   struct TypeCheckTest *data = _data;
606
607   g_object_unref (data->object);
608   g_free (data);
609 }
610
611 /*************************************************************
612  * Test signal emissions performance (common code)
613  *************************************************************/
614
615 #define NUM_EMISSIONS_PER_ROUND 10000
616
617 struct EmissionTest {
618   GObject *object;
619   int n_checks;
620   int signal_id;
621 };
622
623 static void
624 test_emission_run (PerformanceTest *test,
625                              gpointer _data)
626 {
627   struct EmissionTest *data = _data;
628   GObject *object = data->object;
629   int i;
630
631   for (i = 0; i < data->n_checks; i++)
632     g_signal_emit (object, data->signal_id, 0);
633 }
634
635 static void
636 test_emission_run_args (PerformanceTest *test,
637                         gpointer _data)
638 {
639   struct EmissionTest *data = _data;
640   GObject *object = data->object;
641   int i;
642
643   for (i = 0; i < data->n_checks; i++)
644     g_signal_emit (object, data->signal_id, 0, 0, NULL);
645 }
646
647 /*************************************************************
648  * Test signal unhandled emissions performance
649  *************************************************************/
650
651 static gpointer
652 test_emission_unhandled_setup (PerformanceTest *test)
653 {
654   struct EmissionTest *data;
655
656   data = g_new0 (struct EmissionTest, 1);
657   data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
658   data->signal_id = complex_signals[GPOINTER_TO_INT (test->extra_data)];
659   return data;
660 }
661
662 static void
663 test_emission_unhandled_init (PerformanceTest *test,
664                               gpointer _data,
665                               double factor)
666 {
667   struct EmissionTest *data = _data;
668
669   data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
670 }
671
672 static void
673 test_emission_unhandled_finish (PerformanceTest *test,
674                                 gpointer data)
675 {
676 }
677
678 static void
679 test_emission_unhandled_print_result (PerformanceTest *test,
680                                       gpointer _data,
681                                       double time)
682 {
683   struct EmissionTest *data = _data;
684
685   g_print ("Emissions per second: %.0f\n",
686            data->n_checks / time);
687 }
688
689 static void
690 test_emission_unhandled_teardown (PerformanceTest *test,
691                                   gpointer _data)
692 {
693   struct EmissionTest *data = _data;
694
695   g_object_unref (data->object);
696   g_free (data);
697 }
698
699 /*************************************************************
700  * Test signal handled emissions performance
701  *************************************************************/
702
703 static void
704 test_emission_handled_handler (ComplexObject *obj, gpointer data)
705 {
706 }
707
708 static gpointer
709 test_emission_handled_setup (PerformanceTest *test)
710 {
711   struct EmissionTest *data;
712
713   data = g_new0 (struct EmissionTest, 1);
714   data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
715   data->signal_id = complex_signals[GPOINTER_TO_INT (test->extra_data)];
716   g_signal_connect (data->object, "signal",
717                     G_CALLBACK (test_emission_handled_handler),
718                     NULL);
719   g_signal_connect (data->object, "signal-empty",
720                     G_CALLBACK (test_emission_handled_handler),
721                     NULL);
722   g_signal_connect (data->object, "signal-generic",
723                     G_CALLBACK (test_emission_handled_handler),
724                     NULL);
725   g_signal_connect (data->object, "signal-generic-empty",
726                     G_CALLBACK (test_emission_handled_handler),
727                     NULL);
728   g_signal_connect (data->object, "signal-args",
729                     G_CALLBACK (test_emission_handled_handler),
730                     NULL);
731
732   return data;
733 }
734
735 static void
736 test_emission_handled_init (PerformanceTest *test,
737                             gpointer _data,
738                             double factor)
739 {
740   struct EmissionTest *data = _data;
741
742   data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
743 }
744
745 static void
746 test_emission_handled_finish (PerformanceTest *test,
747                               gpointer data)
748 {
749 }
750
751 static void
752 test_emission_handled_print_result (PerformanceTest *test,
753                                     gpointer _data,
754                                     double time)
755 {
756   struct EmissionTest *data = _data;
757
758   g_print ("Emissions per second: %.0f\n",
759            data->n_checks / time);
760 }
761
762 static void
763 test_emission_handled_teardown (PerformanceTest *test,
764                                 gpointer _data)
765 {
766   struct EmissionTest *data = _data;
767
768   g_object_unref (data->object);
769   g_free (data);
770 }
771
772 /*************************************************************
773  * Main test code
774  *************************************************************/
775
776 static PerformanceTest tests[] = {
777   {
778     "simple-construction",
779     simple_object_get_type,
780     test_construction_setup,
781     test_construction_init,
782     test_construction_run,
783     test_construction_finish,
784     test_construction_teardown,
785     test_construction_print_result
786   },
787   {
788     "complex-construction",
789     complex_object_get_type,
790     test_construction_setup,
791     test_construction_init,
792     test_construction_run,
793     test_construction_finish,
794     test_construction_teardown,
795     test_construction_print_result
796   },
797   {
798     "type-check",
799     NULL,
800     test_type_check_setup,
801     test_type_check_init,
802     test_type_check_run,
803     test_type_check_finish,
804     test_type_check_teardown,
805     test_type_check_print_result
806   },
807   {
808     "emit-unhandled",
809     GINT_TO_POINTER (COMPLEX_SIGNAL),
810     test_emission_unhandled_setup,
811     test_emission_unhandled_init,
812     test_emission_run,
813     test_emission_unhandled_finish,
814     test_emission_unhandled_teardown,
815     test_emission_unhandled_print_result
816   },
817   {
818     "emit-unhandled-empty",
819     GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
820     test_emission_unhandled_setup,
821     test_emission_unhandled_init,
822     test_emission_run,
823     test_emission_unhandled_finish,
824     test_emission_unhandled_teardown,
825     test_emission_unhandled_print_result
826   },
827   {
828     "emit-unhandled-generic",
829     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
830     test_emission_unhandled_setup,
831     test_emission_unhandled_init,
832     test_emission_run,
833     test_emission_unhandled_finish,
834     test_emission_unhandled_teardown,
835     test_emission_unhandled_print_result
836   },
837   {
838     "emit-unhandled-generic-empty",
839     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
840     test_emission_unhandled_setup,
841     test_emission_unhandled_init,
842     test_emission_run,
843     test_emission_unhandled_finish,
844     test_emission_unhandled_teardown,
845     test_emission_unhandled_print_result
846   },
847   {
848     "emit-unhandled-args",
849     GINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
850     test_emission_unhandled_setup,
851     test_emission_unhandled_init,
852     test_emission_run_args,
853     test_emission_unhandled_finish,
854     test_emission_unhandled_teardown,
855     test_emission_unhandled_print_result
856   },
857   {
858     "emit-handled",
859     GINT_TO_POINTER (COMPLEX_SIGNAL),
860     test_emission_handled_setup,
861     test_emission_handled_init,
862     test_emission_run,
863     test_emission_handled_finish,
864     test_emission_handled_teardown,
865     test_emission_handled_print_result
866   },
867   {
868     "emit-handled-empty",
869     GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
870     test_emission_handled_setup,
871     test_emission_handled_init,
872     test_emission_run,
873     test_emission_handled_finish,
874     test_emission_handled_teardown,
875     test_emission_handled_print_result
876   },
877   {
878     "emit-handled-generic",
879     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
880     test_emission_handled_setup,
881     test_emission_handled_init,
882     test_emission_run,
883     test_emission_handled_finish,
884     test_emission_handled_teardown,
885     test_emission_handled_print_result
886   },
887   {
888     "emit-handled-generic-empty",
889     GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
890     test_emission_handled_setup,
891     test_emission_handled_init,
892     test_emission_run,
893     test_emission_handled_finish,
894     test_emission_handled_teardown,
895     test_emission_handled_print_result
896   },
897   {
898     "emit-handled-args",
899     GINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
900     test_emission_handled_setup,
901     test_emission_handled_init,
902     test_emission_run_args,
903     test_emission_handled_finish,
904     test_emission_handled_teardown,
905     test_emission_handled_print_result
906   }
907 };
908
909 static PerformanceTest *
910 find_test (const char *name)
911 {
912   int i;
913   for (i = 0; i < G_N_ELEMENTS (tests); i++)
914     {
915       if (strcmp (tests[i].name, name) == 0)
916         return &tests[i];
917     }
918   return NULL;
919 }
920 int
921 main (int   argc,
922       char *argv[])
923 {
924   PerformanceTest *test;
925   GOptionContext *context;
926   GError *error = NULL;
927   int i;
928
929   context = g_option_context_new ("GObject performance tests");
930   g_option_context_add_main_entries (context, cmd_entries, NULL);
931   if (!g_option_context_parse (context, &argc, &argv, &error))
932     {
933       g_printerr ("%s: %s\n", argv[0], error->message);
934       return 1;
935     }
936
937   if (argc > 1)
938     {
939       for (i = 1; i < argc; i++)
940         {
941           test = find_test (argv[i]);
942           if (test)
943             run_test (test);
944         }
945     }
946   else
947     {
948       for (i = 0; i < G_N_ELEMENTS (tests); i++)
949         run_test (&tests[i]);
950     }
951
952   return 0;
953 }