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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <glib-object.h>
23 #include "testcommon.h"
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
32 #define TARGET_ROUND_TIME 0.004
34 static gboolean verbose = FALSE;
35 static int test_length = DEFAULT_TEST_TIME;
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},
45 typedef struct _PerformanceTest PerformanceTest;
46 struct _PerformanceTest {
50 gpointer (*setup) (PerformanceTest *test);
51 void (*init) (PerformanceTest *test,
54 void (*run) (PerformanceTest *test,
56 void (*finish) (PerformanceTest *test,
58 void (*teardown) (PerformanceTest *test,
60 void (*print_result) (PerformanceTest *test,
66 run_test (PerformanceTest *test)
69 guint64 i, num_rounds;
70 double elapsed, min_elapsed, factor;
73 g_print ("Running test %s\n", test->name);
76 timer = g_timer_new ();
77 data = test->setup (test);
80 g_print ("Warming up\n");
82 /* Warm up the test by doing a few runs */
83 for (i = 0; i < WARM_UP_N_RUNS; i++)
85 test->init (test, data, 1.0);
86 test->run (test, data);
87 test->finish (test, data);
91 g_print ("Estimating round time\n");
93 /* Estimate time for one run by doing a few test rounds */
95 for (i = 0; i < ESTIMATE_ROUND_TIME_N_RUNS; i++)
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);
103 elapsed = g_timer_elapsed (timer, NULL);
105 min_elapsed = elapsed;
107 min_elapsed = MIN (min_elapsed, elapsed);
110 factor = TARGET_ROUND_TIME / min_elapsed;
113 g_print ("Uncorrected round time: %f.4 secs, correction factor %f.2\n", min_elapsed, factor);
115 /* Calculate number of rounds needed */
116 num_rounds = (test_length / TARGET_ROUND_TIME) + 1;
119 g_print ("Running %"G_GINT64_MODIFIER"d rounds\n", num_rounds);
122 for (i = 0; i < num_rounds; i++)
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);
132 min_elapsed = elapsed;
134 min_elapsed = MIN (min_elapsed, elapsed);
138 g_print ("Minimum corrected round time: %f secs\n", min_elapsed);
140 /* Print the results */
141 test->print_result (test, data, min_elapsed);
144 test->teardown (test, data);
145 g_timer_destroy (timer);
148 /*************************************************************
149 * Simple object is a very simple small GObject subclass
150 * with no properties, no signals, implementing no interfaces
151 *************************************************************/
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;
160 GObject parent_instance;
164 struct _SimpleObjectClass
166 GObjectClass parent_class;
169 G_DEFINE_TYPE (SimpleObject, simple_object, G_TYPE_OBJECT);
172 simple_object_finalize (GObject *object)
174 G_OBJECT_CLASS (simple_object_parent_class)->finalize (object);
178 simple_object_class_init (SimpleObjectClass *class)
180 GObjectClass *object_class = G_OBJECT_CLASS (class);
182 object_class->finalize = simple_object_finalize;
186 simple_object_init (SimpleObject *simple_object)
188 simple_object->val = 42;
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;
199 struct _TestIfaceClass
201 GTypeInterface base_iface;
202 void (*method) (TestIface *obj);
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);
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 ())
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)
223 /*************************************************************
224 * Complex object is a GObject subclass with a properties,
225 * construct properties, signals and implementing an interface.
226 *************************************************************/
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;
233 struct _ComplexObject
235 GObject parent_instance;
240 struct _ComplexObjectClass
242 GObjectClass parent_class;
244 void (*signal) (ComplexObject *obj);
245 void (*signal_empty) (ComplexObject *obj);
248 static void complex_test_iface_init (gpointer g_iface,
249 gpointer iface_data);
251 G_DEFINE_TYPE_EXTENDED (ComplexObject, complex_object,
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)
265 #define COMPLEX_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), COMPLEX_TYPE_OBJECT, ComplexObject))
275 COMPLEX_SIGNAL_EMPTY,
276 COMPLEX_SIGNAL_GENERIC,
277 COMPLEX_SIGNAL_GENERIC_EMPTY,
282 static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
285 complex_object_finalize (GObject *object)
287 G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
291 complex_object_set_property (GObject *object,
296 ComplexObject *complex = COMPLEX_OBJECT (object);
301 complex->val1 = g_value_get_int (value);
304 complex->val2 = g_value_get_int (value);
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
313 complex_object_get_property (GObject *object,
318 ComplexObject *complex = COMPLEX_OBJECT (object);
323 g_value_set_int (value, complex->val1);
326 g_value_set_int (value, complex->val2);
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
335 complex_object_real_signal (ComplexObject *obj)
340 complex_object_class_init (ComplexObjectClass *class)
342 GObjectClass *object_class = G_OBJECT_CLASS (class);
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;
348 class->signal = complex_object_real_signal;
350 complex_signals[COMPLEX_SIGNAL] =
351 g_signal_new ("signal",
352 G_TYPE_FROM_CLASS (object_class),
354 G_STRUCT_OFFSET (ComplexObjectClass, signal),
356 g_cclosure_marshal_VOID__VOID,
359 complex_signals[COMPLEX_SIGNAL_EMPTY] =
360 g_signal_new ("signal-empty",
361 G_TYPE_FROM_CLASS (object_class),
363 G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
365 g_cclosure_marshal_VOID__VOID,
368 complex_signals[COMPLEX_SIGNAL_GENERIC] =
369 g_signal_new ("signal-generic",
370 G_TYPE_FROM_CLASS (object_class),
372 G_STRUCT_OFFSET (ComplexObjectClass, signal),
376 complex_signals[COMPLEX_SIGNAL_GENERIC_EMPTY] =
377 g_signal_new ("signal-generic-empty",
378 G_TYPE_FROM_CLASS (object_class),
380 G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
385 complex_signals[COMPLEX_SIGNAL_ARGS] =
386 g_signal_new ("signal-args",
387 G_TYPE_FROM_CLASS (object_class),
389 G_STRUCT_OFFSET (ComplexObjectClass, signal),
391 g_cclosure_marshal_VOID__UINT_POINTER,
392 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
394 g_object_class_install_property (object_class,
396 g_param_spec_int ("val1",
402 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
403 g_object_class_install_property (object_class,
405 g_param_spec_int ("val2",
417 complex_object_iface_method (TestIface *obj)
419 ComplexObject *complex = COMPLEX_OBJECT (obj);
424 complex_test_iface_init (gpointer g_iface,
427 TestIfaceClass *iface = g_iface;
428 iface->method = complex_object_iface_method;
432 complex_object_init (ComplexObject *complex_object)
434 complex_object->val2 = 43;
437 /*************************************************************
438 * Test object construction performance
439 *************************************************************/
441 #define NUM_OBJECT_TO_CONSTRUCT 10000
443 struct ConstructionTest {
450 test_construction_setup (PerformanceTest *test)
452 struct ConstructionTest *data;
454 data = g_new0 (struct ConstructionTest, 1);
455 data->type = ((GType (*)(void))test->extra_data)();
461 test_construction_init (PerformanceTest *test,
465 struct ConstructionTest *data = _data;
468 n = NUM_OBJECT_TO_CONSTRUCT * count_factor;
469 if (data->n_objects != n)
472 data->objects = g_new (GObject *, n);
477 test_construction_run (PerformanceTest *test,
480 struct ConstructionTest *data = _data;
481 GObject **objects = data->objects;
482 GType type = data->type;
485 n_objects = data->n_objects;
486 for (i = 0; i < n_objects; i++)
487 objects[i] = g_object_new (type, NULL);
491 test_construction_finish (PerformanceTest *test,
494 struct ConstructionTest *data = _data;
497 for (i = 0; i < data->n_objects; i++)
498 g_object_unref (data->objects[i]);
502 test_construction_teardown (PerformanceTest *test,
505 struct ConstructionTest *data = _data;
506 g_free (data->objects);
511 test_construction_print_result (PerformanceTest *test,
515 struct ConstructionTest *data = _data;
517 g_print ("Number of constructed objects per second: %.0f\n",
518 data->n_objects / time);
521 /*************************************************************
522 * Test runtime type check performance
523 *************************************************************/
525 #define NUM_KILO_CHECKS_PER_ROUND 50
527 struct TypeCheckTest {
533 test_type_check_setup (PerformanceTest *test)
535 struct TypeCheckTest *data;
537 data = g_new0 (struct TypeCheckTest, 1);
538 data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
544 test_type_check_init (PerformanceTest *test,
548 struct TypeCheckTest *data = _data;
550 data->n_checks = factor * NUM_KILO_CHECKS_PER_ROUND;
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;
560 test_type_check_run (PerformanceTest *test,
563 struct TypeCheckTest *data = _data;
564 volatile GObject *object = data->object;
565 volatile GType type, types[5];
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 ();
574 for (i = 0; i < data->n_checks; i++)
577 for (j = 0; j < 1000; j++)
579 my_type_check_instance_is_a ((GTypeInstance *)object,
586 test_type_check_finish (PerformanceTest *test,
592 test_type_check_print_result (PerformanceTest *test,
596 struct TypeCheckTest *data = _data;
597 g_print ("Million type checks per second: %.2f\n",
598 data->n_checks / (1000*time));
602 test_type_check_teardown (PerformanceTest *test,
605 struct TypeCheckTest *data = _data;
607 g_object_unref (data->object);
611 /*************************************************************
612 * Test signal emissions performance (common code)
613 *************************************************************/
615 #define NUM_EMISSIONS_PER_ROUND 10000
617 struct EmissionTest {
624 test_emission_run (PerformanceTest *test,
627 struct EmissionTest *data = _data;
628 GObject *object = data->object;
631 for (i = 0; i < data->n_checks; i++)
632 g_signal_emit (object, data->signal_id, 0);
636 test_emission_run_args (PerformanceTest *test,
639 struct EmissionTest *data = _data;
640 GObject *object = data->object;
643 for (i = 0; i < data->n_checks; i++)
644 g_signal_emit (object, data->signal_id, 0, 0, NULL);
647 /*************************************************************
648 * Test signal unhandled emissions performance
649 *************************************************************/
652 test_emission_unhandled_setup (PerformanceTest *test)
654 struct EmissionTest *data;
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)];
663 test_emission_unhandled_init (PerformanceTest *test,
667 struct EmissionTest *data = _data;
669 data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
673 test_emission_unhandled_finish (PerformanceTest *test,
679 test_emission_unhandled_print_result (PerformanceTest *test,
683 struct EmissionTest *data = _data;
685 g_print ("Emissions per second: %.0f\n",
686 data->n_checks / time);
690 test_emission_unhandled_teardown (PerformanceTest *test,
693 struct EmissionTest *data = _data;
695 g_object_unref (data->object);
699 /*************************************************************
700 * Test signal handled emissions performance
701 *************************************************************/
704 test_emission_handled_handler (ComplexObject *obj, gpointer data)
709 test_emission_handled_setup (PerformanceTest *test)
711 struct EmissionTest *data;
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),
719 g_signal_connect (data->object, "signal-empty",
720 G_CALLBACK (test_emission_handled_handler),
722 g_signal_connect (data->object, "signal-generic",
723 G_CALLBACK (test_emission_handled_handler),
725 g_signal_connect (data->object, "signal-generic-empty",
726 G_CALLBACK (test_emission_handled_handler),
728 g_signal_connect (data->object, "signal-args",
729 G_CALLBACK (test_emission_handled_handler),
736 test_emission_handled_init (PerformanceTest *test,
740 struct EmissionTest *data = _data;
742 data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
746 test_emission_handled_finish (PerformanceTest *test,
752 test_emission_handled_print_result (PerformanceTest *test,
756 struct EmissionTest *data = _data;
758 g_print ("Emissions per second: %.0f\n",
759 data->n_checks / time);
763 test_emission_handled_teardown (PerformanceTest *test,
766 struct EmissionTest *data = _data;
768 g_object_unref (data->object);
772 /*************************************************************
774 *************************************************************/
776 static PerformanceTest tests[] = {
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
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
800 test_type_check_setup,
801 test_type_check_init,
803 test_type_check_finish,
804 test_type_check_teardown,
805 test_type_check_print_result
809 GINT_TO_POINTER (COMPLEX_SIGNAL),
810 test_emission_unhandled_setup,
811 test_emission_unhandled_init,
813 test_emission_unhandled_finish,
814 test_emission_unhandled_teardown,
815 test_emission_unhandled_print_result
818 "emit-unhandled-empty",
819 GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
820 test_emission_unhandled_setup,
821 test_emission_unhandled_init,
823 test_emission_unhandled_finish,
824 test_emission_unhandled_teardown,
825 test_emission_unhandled_print_result
828 "emit-unhandled-generic",
829 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
830 test_emission_unhandled_setup,
831 test_emission_unhandled_init,
833 test_emission_unhandled_finish,
834 test_emission_unhandled_teardown,
835 test_emission_unhandled_print_result
838 "emit-unhandled-generic-empty",
839 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
840 test_emission_unhandled_setup,
841 test_emission_unhandled_init,
843 test_emission_unhandled_finish,
844 test_emission_unhandled_teardown,
845 test_emission_unhandled_print_result
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
859 GINT_TO_POINTER (COMPLEX_SIGNAL),
860 test_emission_handled_setup,
861 test_emission_handled_init,
863 test_emission_handled_finish,
864 test_emission_handled_teardown,
865 test_emission_handled_print_result
868 "emit-handled-empty",
869 GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
870 test_emission_handled_setup,
871 test_emission_handled_init,
873 test_emission_handled_finish,
874 test_emission_handled_teardown,
875 test_emission_handled_print_result
878 "emit-handled-generic",
879 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
880 test_emission_handled_setup,
881 test_emission_handled_init,
883 test_emission_handled_finish,
884 test_emission_handled_teardown,
885 test_emission_handled_print_result
888 "emit-handled-generic-empty",
889 GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
890 test_emission_handled_setup,
891 test_emission_handled_init,
893 test_emission_handled_finish,
894 test_emission_handled_teardown,
895 test_emission_handled_print_result
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
909 static PerformanceTest *
910 find_test (const char *name)
913 for (i = 0; i < G_N_ELEMENTS (tests); i++)
915 if (strcmp (tests[i].name, name) == 0)
924 PerformanceTest *test;
925 GOptionContext *context;
926 GError *error = NULL;
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))
933 g_printerr ("%s: %s\n", argv[0], error->message);
939 for (i = 1; i < argc; i++)
941 test = find_test (argv[i]);
948 for (i = 0; i < G_N_ELEMENTS (tests); i++)
949 run_test (&tests[i]);