1 /* GObject - GLib Type, Object, Parameter and Signal Library
2 * Copyright (C) 2009 Red Hat, Inc.
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.
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.
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/>.
20 #include <glib-object.h>
21 #include "testcommon.h"
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 * enought that the risk of any random slowness will miss the
30 #define TARGET_ROUND_TIME 0.004
32 static gboolean verbose
= FALSE
;
33 static int test_length
= DEFAULT_TEST_TIME
;
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
},
43 typedef struct _PerformanceTest PerformanceTest
;
44 struct _PerformanceTest
{
48 gpointer (*setup
) (PerformanceTest
*test
);
49 void (*init
) (PerformanceTest
*test
,
52 void (*run
) (PerformanceTest
*test
,
54 void (*finish
) (PerformanceTest
*test
,
56 void (*teardown
) (PerformanceTest
*test
,
58 void (*print_result
) (PerformanceTest
*test
,
64 run_test (PerformanceTest
*test
)
67 guint64 i
, num_rounds
;
68 double elapsed
, min_elapsed
, factor
;
71 g_print ("Running test %s\n", test
->name
);
74 timer
= g_timer_new ();
75 data
= test
->setup (test
);
78 g_print ("Warming up\n");
80 /* Warm up the test by doing a few runs */
81 for (i
= 0; i
< WARM_UP_N_RUNS
; i
++)
83 test
->init (test
, data
, 1.0);
84 test
->run (test
, data
);
85 test
->finish (test
, data
);
89 g_print ("Estimating round time\n");
91 /* Estimate time for one run by doing a few test rounds */
93 for (i
= 0; i
< ESTIMATE_ROUND_TIME_N_RUNS
; i
++)
95 test
->init (test
, data
, 1.0);
96 g_timer_start (timer
);
97 test
->run (test
, data
);
99 test
->finish (test
, data
);
101 elapsed
= g_timer_elapsed (timer
, NULL
);
103 min_elapsed
= elapsed
;
105 min_elapsed
= MIN (min_elapsed
, elapsed
);
108 factor
= TARGET_ROUND_TIME
/ min_elapsed
;
111 g_print ("Uncorrected round time: %f.4 secs, correction factor %f.2\n", min_elapsed
, factor
);
113 /* Calculate number of rounds needed */
114 num_rounds
= (test_length
/ TARGET_ROUND_TIME
) + 1;
117 g_print ("Running %"G_GINT64_MODIFIER
"d rounds\n", num_rounds
);
120 for (i
= 0; i
< num_rounds
; i
++)
122 test
->init (test
, data
, factor
);
123 g_timer_start (timer
);
124 test
->run (test
, data
);
125 g_timer_stop (timer
);
126 test
->finish (test
, data
);
127 elapsed
= g_timer_elapsed (timer
, NULL
);
130 min_elapsed
= elapsed
;
132 min_elapsed
= MIN (min_elapsed
, elapsed
);
136 g_print ("Minimum corrected round time: %f secs\n", min_elapsed
);
138 /* Print the results */
139 test
->print_result (test
, data
, min_elapsed
);
142 test
->teardown (test
, data
);
143 g_timer_destroy (timer
);
146 /*************************************************************
147 * Simple object is a very simple small GObject subclass
148 * with no properties, no signals, implementing no interfaces
149 *************************************************************/
151 static GType
simple_object_get_type (void);
152 #define SIMPLE_TYPE_OBJECT (simple_object_get_type ())
153 typedef struct _SimpleObject SimpleObject
;
154 typedef struct _SimpleObjectClass SimpleObjectClass
;
158 GObject parent_instance
;
162 struct _SimpleObjectClass
164 GObjectClass parent_class
;
167 G_DEFINE_TYPE (SimpleObject
, simple_object
, G_TYPE_OBJECT
);
170 simple_object_finalize (GObject
*object
)
172 G_OBJECT_CLASS (simple_object_parent_class
)->finalize (object
);
176 simple_object_class_init (SimpleObjectClass
*class)
178 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
180 object_class
->finalize
= simple_object_finalize
;
184 simple_object_init (SimpleObject
*simple_object
)
186 simple_object
->val
= 42;
189 typedef struct _TestIfaceClass TestIfaceClass
;
190 typedef struct _TestIfaceClass TestIface1Class
;
191 typedef struct _TestIfaceClass TestIface2Class
;
192 typedef struct _TestIfaceClass TestIface3Class
;
193 typedef struct _TestIfaceClass TestIface4Class
;
194 typedef struct _TestIfaceClass TestIface5Class
;
195 typedef struct _TestIface TestIface
;
197 struct _TestIfaceClass
199 GTypeInterface base_iface
;
200 void (*method
) (TestIface
*obj
);
203 static GType
test_iface1_get_type (void);
204 static GType
test_iface2_get_type (void);
205 static GType
test_iface3_get_type (void);
206 static GType
test_iface4_get_type (void);
207 static GType
test_iface5_get_type (void);
209 #define TEST_TYPE_IFACE1 (test_iface1_get_type ())
210 #define TEST_TYPE_IFACE2 (test_iface2_get_type ())
211 #define TEST_TYPE_IFACE3 (test_iface3_get_type ())
212 #define TEST_TYPE_IFACE4 (test_iface4_get_type ())
213 #define TEST_TYPE_IFACE5 (test_iface5_get_type ())
215 static DEFINE_IFACE (TestIface1
, test_iface1
, NULL
, NULL
)
216 static DEFINE_IFACE (TestIface2
, test_iface2
, NULL
, NULL
)
217 static DEFINE_IFACE (TestIface3
, test_iface3
, NULL
, NULL
)
218 static DEFINE_IFACE (TestIface4
, test_iface4
, NULL
, NULL
)
219 static DEFINE_IFACE (TestIface5
, test_iface5
, NULL
, NULL
)
221 /*************************************************************
222 * Complex object is a GObject subclass with a properties,
223 * construct properties, signals and implementing an interface.
224 *************************************************************/
226 static GType
complex_object_get_type (void);
227 #define COMPLEX_TYPE_OBJECT (complex_object_get_type ())
228 typedef struct _ComplexObject ComplexObject
;
229 typedef struct _ComplexObjectClass ComplexObjectClass
;
231 struct _ComplexObject
233 GObject parent_instance
;
238 struct _ComplexObjectClass
240 GObjectClass parent_class
;
242 void (*signal
) (ComplexObject
*obj
);
243 void (*signal_empty
) (ComplexObject
*obj
);
246 static void complex_test_iface_init (gpointer g_iface
,
247 gpointer iface_data
);
249 G_DEFINE_TYPE_EXTENDED (ComplexObject
, complex_object
,
251 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE1
,
252 complex_test_iface_init
)
253 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE2
,
254 complex_test_iface_init
)
255 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE3
,
256 complex_test_iface_init
)
257 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE4
,
258 complex_test_iface_init
)
259 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE5
,
260 complex_test_iface_init
)
263 #define COMPLEX_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), COMPLEX_TYPE_OBJECT, ComplexObject))
273 COMPLEX_SIGNAL_EMPTY
,
274 COMPLEX_SIGNAL_GENERIC
,
275 COMPLEX_SIGNAL_GENERIC_EMPTY
,
280 static guint complex_signals
[COMPLEX_LAST_SIGNAL
] = { 0 };
283 complex_object_finalize (GObject
*object
)
285 G_OBJECT_CLASS (complex_object_parent_class
)->finalize (object
);
289 complex_object_set_property (GObject
*object
,
294 ComplexObject
*complex = COMPLEX_OBJECT (object
);
299 complex->val1
= g_value_get_int (value
);
302 complex->val2
= g_value_get_int (value
);
305 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
311 complex_object_get_property (GObject
*object
,
316 ComplexObject
*complex = COMPLEX_OBJECT (object
);
321 g_value_set_int (value
, complex->val1
);
324 g_value_set_int (value
, complex->val2
);
327 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
333 complex_object_real_signal (ComplexObject
*obj
)
338 complex_object_class_init (ComplexObjectClass
*class)
340 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
342 object_class
->finalize
= complex_object_finalize
;
343 object_class
->set_property
= complex_object_set_property
;
344 object_class
->get_property
= complex_object_get_property
;
346 class->signal
= complex_object_real_signal
;
348 complex_signals
[COMPLEX_SIGNAL
] =
349 g_signal_new ("signal",
350 G_TYPE_FROM_CLASS (object_class
),
352 G_STRUCT_OFFSET (ComplexObjectClass
, signal
),
354 g_cclosure_marshal_VOID__VOID
,
357 complex_signals
[COMPLEX_SIGNAL_EMPTY
] =
358 g_signal_new ("signal-empty",
359 G_TYPE_FROM_CLASS (object_class
),
361 G_STRUCT_OFFSET (ComplexObjectClass
, signal_empty
),
363 g_cclosure_marshal_VOID__VOID
,
366 complex_signals
[COMPLEX_SIGNAL_GENERIC
] =
367 g_signal_new ("signal-generic",
368 G_TYPE_FROM_CLASS (object_class
),
370 G_STRUCT_OFFSET (ComplexObjectClass
, signal
),
374 complex_signals
[COMPLEX_SIGNAL_GENERIC_EMPTY
] =
375 g_signal_new ("signal-generic-empty",
376 G_TYPE_FROM_CLASS (object_class
),
378 G_STRUCT_OFFSET (ComplexObjectClass
, signal_empty
),
383 complex_signals
[COMPLEX_SIGNAL_ARGS
] =
384 g_signal_new ("signal-args",
385 G_TYPE_FROM_CLASS (object_class
),
387 G_STRUCT_OFFSET (ComplexObjectClass
, signal
),
389 g_cclosure_marshal_VOID__UINT_POINTER
,
390 G_TYPE_NONE
, 2, G_TYPE_UINT
, G_TYPE_POINTER
);
392 g_object_class_install_property (object_class
,
394 g_param_spec_int ("val1",
400 G_PARAM_CONSTRUCT
| G_PARAM_READWRITE
));
401 g_object_class_install_property (object_class
,
403 g_param_spec_int ("val2",
415 complex_object_iface_method (TestIface
*obj
)
417 ComplexObject
*complex = COMPLEX_OBJECT (obj
);
422 complex_test_iface_init (gpointer g_iface
,
425 TestIfaceClass
*iface
= g_iface
;
426 iface
->method
= complex_object_iface_method
;
430 complex_object_init (ComplexObject
*complex_object
)
432 complex_object
->val2
= 43;
435 /*************************************************************
436 * Test object construction performance
437 *************************************************************/
439 #define NUM_OBJECT_TO_CONSTRUCT 10000
441 struct ConstructionTest
{
448 test_construction_setup (PerformanceTest
*test
)
450 struct ConstructionTest
*data
;
452 data
= g_new0 (struct ConstructionTest
, 1);
453 data
->type
= ((GType (*)(void))test
->extra_data
)();
459 test_construction_init (PerformanceTest
*test
,
463 struct ConstructionTest
*data
= _data
;
466 n
= NUM_OBJECT_TO_CONSTRUCT
* count_factor
;
467 if (data
->n_objects
!= n
)
470 data
->objects
= g_new (GObject
*, n
);
475 test_construction_run (PerformanceTest
*test
,
478 struct ConstructionTest
*data
= _data
;
479 GObject
**objects
= data
->objects
;
480 GType type
= data
->type
;
483 n_objects
= data
->n_objects
;
484 for (i
= 0; i
< n_objects
; i
++)
485 objects
[i
] = g_object_new (type
, NULL
);
489 test_construction_finish (PerformanceTest
*test
,
492 struct ConstructionTest
*data
= _data
;
495 for (i
= 0; i
< data
->n_objects
; i
++)
496 g_object_unref (data
->objects
[i
]);
500 test_construction_teardown (PerformanceTest
*test
,
503 struct ConstructionTest
*data
= _data
;
504 g_free (data
->objects
);
509 test_construction_print_result (PerformanceTest
*test
,
513 struct ConstructionTest
*data
= _data
;
515 g_print ("Number of constructed objects per second: %.0f\n",
516 data
->n_objects
/ time
);
519 /*************************************************************
520 * Test runtime type check performance
521 *************************************************************/
523 #define NUM_KILO_CHECKS_PER_ROUND 50
525 struct TypeCheckTest
{
531 test_type_check_setup (PerformanceTest
*test
)
533 struct TypeCheckTest
*data
;
535 data
= g_new0 (struct TypeCheckTest
, 1);
536 data
->object
= g_object_new (COMPLEX_TYPE_OBJECT
, NULL
);
542 test_type_check_init (PerformanceTest
*test
,
546 struct TypeCheckTest
*data
= _data
;
548 data
->n_checks
= factor
* NUM_KILO_CHECKS_PER_ROUND
;
552 /* Work around g_type_check_instance_is_a being marked "pure",
553 and thus only called once for the loop. */
554 gboolean (*my_type_check_instance_is_a
) (GTypeInstance
*type_instance
,
555 GType iface_type
) = &g_type_check_instance_is_a
;
558 test_type_check_run (PerformanceTest
*test
,
561 struct TypeCheckTest
*data
= _data
;
562 volatile GObject
*object
= data
->object
;
563 volatile GType type
, types
[5];
566 types
[0] = test_iface1_get_type ();
567 types
[1] = test_iface2_get_type ();
568 types
[2] = test_iface3_get_type ();
569 types
[3] = test_iface4_get_type ();
570 types
[4] = test_iface5_get_type ();
572 for (i
= 0; i
< data
->n_checks
; i
++)
575 for (j
= 0; j
< 1000; j
++)
577 my_type_check_instance_is_a ((GTypeInstance
*)object
,
584 test_type_check_finish (PerformanceTest
*test
,
590 test_type_check_print_result (PerformanceTest
*test
,
594 struct TypeCheckTest
*data
= _data
;
595 g_print ("Million type checks per second: %.2f\n",
596 data
->n_checks
/ (1000*time
));
600 test_type_check_teardown (PerformanceTest
*test
,
603 struct TypeCheckTest
*data
= _data
;
605 g_object_unref (data
->object
);
609 /*************************************************************
610 * Test signal emissions performance (common code)
611 *************************************************************/
613 #define NUM_EMISSIONS_PER_ROUND 10000
615 struct EmissionTest
{
622 test_emission_run (PerformanceTest
*test
,
625 struct EmissionTest
*data
= _data
;
626 GObject
*object
= data
->object
;
629 for (i
= 0; i
< data
->n_checks
; i
++)
630 g_signal_emit (object
, data
->signal_id
, 0);
634 test_emission_run_args (PerformanceTest
*test
,
637 struct EmissionTest
*data
= _data
;
638 GObject
*object
= data
->object
;
641 for (i
= 0; i
< data
->n_checks
; i
++)
642 g_signal_emit (object
, data
->signal_id
, 0, 0, NULL
);
645 /*************************************************************
646 * Test signal unhandled emissions performance
647 *************************************************************/
650 test_emission_unhandled_setup (PerformanceTest
*test
)
652 struct EmissionTest
*data
;
654 data
= g_new0 (struct EmissionTest
, 1);
655 data
->object
= g_object_new (COMPLEX_TYPE_OBJECT
, NULL
);
656 data
->signal_id
= complex_signals
[GPOINTER_TO_INT (test
->extra_data
)];
661 test_emission_unhandled_init (PerformanceTest
*test
,
665 struct EmissionTest
*data
= _data
;
667 data
->n_checks
= factor
* NUM_EMISSIONS_PER_ROUND
;
671 test_emission_unhandled_finish (PerformanceTest
*test
,
677 test_emission_unhandled_print_result (PerformanceTest
*test
,
681 struct EmissionTest
*data
= _data
;
683 g_print ("Emissions per second: %.0f\n",
684 data
->n_checks
/ time
);
688 test_emission_unhandled_teardown (PerformanceTest
*test
,
691 struct EmissionTest
*data
= _data
;
693 g_object_unref (data
->object
);
697 /*************************************************************
698 * Test signal handled emissions performance
699 *************************************************************/
702 test_emission_handled_handler (ComplexObject
*obj
, gpointer data
)
707 test_emission_handled_setup (PerformanceTest
*test
)
709 struct EmissionTest
*data
;
711 data
= g_new0 (struct EmissionTest
, 1);
712 data
->object
= g_object_new (COMPLEX_TYPE_OBJECT
, NULL
);
713 data
->signal_id
= complex_signals
[GPOINTER_TO_INT (test
->extra_data
)];
714 g_signal_connect (data
->object
, "signal",
715 G_CALLBACK (test_emission_handled_handler
),
717 g_signal_connect (data
->object
, "signal-empty",
718 G_CALLBACK (test_emission_handled_handler
),
720 g_signal_connect (data
->object
, "signal-generic",
721 G_CALLBACK (test_emission_handled_handler
),
723 g_signal_connect (data
->object
, "signal-generic-empty",
724 G_CALLBACK (test_emission_handled_handler
),
726 g_signal_connect (data
->object
, "signal-args",
727 G_CALLBACK (test_emission_handled_handler
),
734 test_emission_handled_init (PerformanceTest
*test
,
738 struct EmissionTest
*data
= _data
;
740 data
->n_checks
= factor
* NUM_EMISSIONS_PER_ROUND
;
744 test_emission_handled_finish (PerformanceTest
*test
,
750 test_emission_handled_print_result (PerformanceTest
*test
,
754 struct EmissionTest
*data
= _data
;
756 g_print ("Emissions per second: %.0f\n",
757 data
->n_checks
/ time
);
761 test_emission_handled_teardown (PerformanceTest
*test
,
764 struct EmissionTest
*data
= _data
;
766 g_object_unref (data
->object
);
770 /*************************************************************
772 *************************************************************/
774 static PerformanceTest tests
[] = {
776 "simple-construction",
777 simple_object_get_type
,
778 test_construction_setup
,
779 test_construction_init
,
780 test_construction_run
,
781 test_construction_finish
,
782 test_construction_teardown
,
783 test_construction_print_result
786 "complex-construction",
787 complex_object_get_type
,
788 test_construction_setup
,
789 test_construction_init
,
790 test_construction_run
,
791 test_construction_finish
,
792 test_construction_teardown
,
793 test_construction_print_result
798 test_type_check_setup
,
799 test_type_check_init
,
801 test_type_check_finish
,
802 test_type_check_teardown
,
803 test_type_check_print_result
807 GINT_TO_POINTER (COMPLEX_SIGNAL
),
808 test_emission_unhandled_setup
,
809 test_emission_unhandled_init
,
811 test_emission_unhandled_finish
,
812 test_emission_unhandled_teardown
,
813 test_emission_unhandled_print_result
816 "emit-unhandled-empty",
817 GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY
),
818 test_emission_unhandled_setup
,
819 test_emission_unhandled_init
,
821 test_emission_unhandled_finish
,
822 test_emission_unhandled_teardown
,
823 test_emission_unhandled_print_result
826 "emit-unhandled-generic",
827 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC
),
828 test_emission_unhandled_setup
,
829 test_emission_unhandled_init
,
831 test_emission_unhandled_finish
,
832 test_emission_unhandled_teardown
,
833 test_emission_unhandled_print_result
836 "emit-unhandled-generic-empty",
837 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY
),
838 test_emission_unhandled_setup
,
839 test_emission_unhandled_init
,
841 test_emission_unhandled_finish
,
842 test_emission_unhandled_teardown
,
843 test_emission_unhandled_print_result
846 "emit-unhandled-args",
847 GINT_TO_POINTER (COMPLEX_SIGNAL_ARGS
),
848 test_emission_unhandled_setup
,
849 test_emission_unhandled_init
,
850 test_emission_run_args
,
851 test_emission_unhandled_finish
,
852 test_emission_unhandled_teardown
,
853 test_emission_unhandled_print_result
857 GINT_TO_POINTER (COMPLEX_SIGNAL
),
858 test_emission_handled_setup
,
859 test_emission_handled_init
,
861 test_emission_handled_finish
,
862 test_emission_handled_teardown
,
863 test_emission_handled_print_result
866 "emit-handled-empty",
867 GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY
),
868 test_emission_handled_setup
,
869 test_emission_handled_init
,
871 test_emission_handled_finish
,
872 test_emission_handled_teardown
,
873 test_emission_handled_print_result
876 "emit-handled-generic",
877 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC
),
878 test_emission_handled_setup
,
879 test_emission_handled_init
,
881 test_emission_handled_finish
,
882 test_emission_handled_teardown
,
883 test_emission_handled_print_result
886 "emit-handled-generic-empty",
887 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY
),
888 test_emission_handled_setup
,
889 test_emission_handled_init
,
891 test_emission_handled_finish
,
892 test_emission_handled_teardown
,
893 test_emission_handled_print_result
897 GINT_TO_POINTER (COMPLEX_SIGNAL_ARGS
),
898 test_emission_handled_setup
,
899 test_emission_handled_init
,
900 test_emission_run_args
,
901 test_emission_handled_finish
,
902 test_emission_handled_teardown
,
903 test_emission_handled_print_result
907 static PerformanceTest
*
908 find_test (const char *name
)
911 for (i
= 0; i
< G_N_ELEMENTS (tests
); i
++)
913 if (strcmp (tests
[i
].name
, name
) == 0)
922 PerformanceTest
*test
;
923 GOptionContext
*context
;
924 GError
*error
= NULL
;
927 context
= g_option_context_new ("GObject performance tests");
928 g_option_context_add_main_entries (context
, cmd_entries
, NULL
);
929 if (!g_option_context_parse (context
, &argc
, &argv
, &error
))
931 g_printerr ("%s: %s\n", argv
[0], error
->message
);
937 for (i
= 1; i
< argc
; i
++)
939 test
= find_test (argv
[i
]);
946 for (i
= 0; i
< G_N_ELEMENTS (tests
); i
++)
947 run_test (&tests
[i
]);