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