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