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 gboolean init_threads = FALSE;
36 static int test_length = DEFAULT_TEST_TIME;
38 static GOptionEntry cmd_entries[] = {
39 {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
40 "Print extra information", NULL},
41 {"threads", 't', 0, G_OPTION_ARG_NONE, &init_threads,
42 "Initialize threads", NULL},
43 {"seconds", 's', 0, G_OPTION_ARG_INT, &test_length,
44 "Time to run each test in seconds", NULL},
48 typedef struct _PerformanceTest PerformanceTest;
49 struct _PerformanceTest {
53 gpointer (*setup) (PerformanceTest *test);
54 void (*init) (PerformanceTest *test,
57 void (*run) (PerformanceTest *test,
59 void (*finish) (PerformanceTest *test,
61 void (*teardown) (PerformanceTest *test,
63 void (*print_result) (PerformanceTest *test,
69 run_test (PerformanceTest *test)
72 guint64 i, num_rounds;
73 double elapsed, min_elapsed, factor;
76 g_print ("Running test %s\n", test->name);
79 timer = g_timer_new ();
80 data = test->setup (test);
83 g_print ("Warming up\n");
85 /* Warm up the test by doing a few runs */
86 for (i = 0; i < WARM_UP_N_RUNS; i++)
88 test->init (test, data, 1.0);
89 test->run (test, data);
90 test->finish (test, data);
94 g_print ("Estimating round time\n");
96 /* Estimate time for one run by doing a few test rounds */
98 for (i = 0; i < ESTIMATE_ROUND_TIME_N_RUNS; i++)
100 test->init (test, data, 1.0);
101 g_timer_start (timer);
102 test->run (test, data);
103 g_timer_stop (timer);
104 test->finish (test, data);
106 elapsed = g_timer_elapsed (timer, NULL);
108 min_elapsed = elapsed;
110 min_elapsed = MIN (min_elapsed, elapsed);
113 factor = TARGET_ROUND_TIME / min_elapsed;
116 g_print ("Uncorrected round time: %f.4 secs, correction factor %f.2\n", min_elapsed, factor);
118 /* Calculate number of rounds needed */
119 num_rounds = (test_length / TARGET_ROUND_TIME) + 1;
122 g_print ("Running %"G_GINT64_MODIFIER"d rounds\n", num_rounds);
125 for (i = 0; i < num_rounds; i++)
127 test->init (test, data, factor);
128 g_timer_start (timer);
129 test->run (test, data);
130 g_timer_stop (timer);
131 test->finish (test, data);
132 elapsed = g_timer_elapsed (timer, NULL);
135 min_elapsed = elapsed;
137 min_elapsed = MIN (min_elapsed, elapsed);
141 g_print ("Minimum corrected round time: %f secs\n", min_elapsed);
143 /* Print the results */
144 test->print_result (test, data, min_elapsed);
147 test->teardown (test, data);
148 g_timer_destroy (timer);
151 /*************************************************************
152 * Simple object is a very simple small GObject subclass
153 * with no properties, no signals, implementing no interfaces
154 *************************************************************/
156 #define SIMPLE_TYPE_OBJECT (simple_object_get_type ())
157 typedef struct _SimpleObject SimpleObject;
158 typedef struct _SimpleObjectClass SimpleObjectClass;
162 GObject parent_instance;
166 struct _SimpleObjectClass
168 GObjectClass parent_class;
171 G_DEFINE_TYPE (SimpleObject, simple_object, G_TYPE_OBJECT);
174 simple_object_finalize (GObject *object)
176 G_OBJECT_CLASS (simple_object_parent_class)->finalize (object);
180 simple_object_class_init (SimpleObjectClass *class)
182 GObjectClass *object_class = G_OBJECT_CLASS (class);
184 object_class->finalize = simple_object_finalize;
188 simple_object_init (SimpleObject *simple_object)
190 simple_object->val = 42;
193 typedef struct _TestIfaceClass TestIfaceClass;
194 typedef struct _TestIfaceClass TestIface1Class;
195 typedef struct _TestIfaceClass TestIface2Class;
196 typedef struct _TestIfaceClass TestIface3Class;
197 typedef struct _TestIfaceClass TestIface4Class;
198 typedef struct _TestIfaceClass TestIface5Class;
199 typedef struct _TestIface TestIface;
201 struct _TestIfaceClass
203 GTypeInterface base_iface;
204 void (*method) (TestIface *obj);
207 #define TEST_TYPE_IFACE1 (test_iface1_get_type ())
208 #define TEST_TYPE_IFACE2 (test_iface2_get_type ())
209 #define TEST_TYPE_IFACE3 (test_iface3_get_type ())
210 #define TEST_TYPE_IFACE4 (test_iface4_get_type ())
211 #define TEST_TYPE_IFACE5 (test_iface5_get_type ())
213 static DEFINE_IFACE (TestIface1, test_iface1, NULL, NULL)
214 static DEFINE_IFACE (TestIface2, test_iface2, NULL, NULL)
215 static DEFINE_IFACE (TestIface3, test_iface3, NULL, NULL)
216 static DEFINE_IFACE (TestIface4, test_iface4, NULL, NULL)
217 static DEFINE_IFACE (TestIface5, test_iface5, NULL, NULL)
219 /*************************************************************
220 * Complex object is a GObject subclass with a properties,
221 * construct properties, signals and implementing an interface.
222 *************************************************************/
224 #define COMPLEX_TYPE_OBJECT (complex_object_get_type ())
225 typedef struct _ComplexObject ComplexObject;
226 typedef struct _ComplexObjectClass ComplexObjectClass;
228 struct _ComplexObject
230 GObject parent_instance;
235 struct _ComplexObjectClass
237 GObjectClass parent_class;
239 void (*signal) (ComplexObject *obj);
242 static void complex_test_iface_init (gpointer g_iface,
243 gpointer iface_data);
245 G_DEFINE_TYPE_EXTENDED (ComplexObject, complex_object,
247 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE1,
248 complex_test_iface_init)
249 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE2,
250 complex_test_iface_init)
251 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE3,
252 complex_test_iface_init)
253 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE4,
254 complex_test_iface_init)
255 G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE5,
256 complex_test_iface_init)
259 #define COMPLEX_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), COMPLEX_TYPE_OBJECT, ComplexObject))
272 static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
275 complex_object_finalize (GObject *object)
277 G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
281 complex_object_set_property (GObject *object,
286 ComplexObject *complex = COMPLEX_OBJECT (object);
291 complex->val1 = g_value_get_int (value);
294 complex->val2 = g_value_get_int (value);
297 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
303 complex_object_get_property (GObject *object,
308 ComplexObject *complex = COMPLEX_OBJECT (object);
313 g_value_set_int (value, complex->val1);
316 g_value_set_int (value, complex->val2);
319 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
325 complex_object_real_signal (ComplexObject *obj)
330 complex_object_class_init (ComplexObjectClass *class)
332 GObjectClass *object_class = G_OBJECT_CLASS (class);
334 object_class->finalize = complex_object_finalize;
335 object_class->set_property = complex_object_set_property;
336 object_class->get_property = complex_object_get_property;
337 class->signal = complex_object_real_signal;
339 complex_signals[COMPLEX_SIGNAL] =
340 g_signal_new ("signal",
341 G_TYPE_FROM_CLASS (object_class),
343 G_STRUCT_OFFSET (ComplexObjectClass, signal),
345 g_cclosure_marshal_VOID__VOID,
348 g_object_class_install_property (object_class,
350 g_param_spec_int ("val1",
356 G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
357 g_object_class_install_property (object_class,
359 g_param_spec_int ("val2",
371 complex_object_iface_method (TestIface *obj)
373 ComplexObject *complex = COMPLEX_OBJECT (obj);
378 complex_test_iface_init (gpointer g_iface,
381 TestIfaceClass *iface = g_iface;
382 iface->method = complex_object_iface_method;
386 complex_object_init (ComplexObject *complex_object)
388 complex_object->val2 = 43;
391 /*************************************************************
392 * Test object construction performance
393 *************************************************************/
395 #define NUM_OBJECT_TO_CONSTRUCT 10000
397 struct ConstructionTest {
404 test_construction_setup (PerformanceTest *test)
406 struct ConstructionTest *data;
408 data = g_new0 (struct ConstructionTest, 1);
409 data->type = ((GType (*)())test->extra_data)();
415 test_construction_init (PerformanceTest *test,
419 struct ConstructionTest *data = _data;
422 n = NUM_OBJECT_TO_CONSTRUCT * count_factor;
423 if (data->n_objects != n)
426 data->objects = g_new (GObject *, n);
431 test_construction_run (PerformanceTest *test,
434 struct ConstructionTest *data = _data;
435 GObject **objects = data->objects;
436 GType type = data->type;
439 n_objects = data->n_objects;
440 for (i = 0; i < n_objects; i++)
441 objects[i] = g_object_new (type, NULL);
445 test_construction_finish (PerformanceTest *test,
448 struct ConstructionTest *data = _data;
451 for (i = 0; i < data->n_objects; i++)
452 g_object_unref (data->objects[i]);
456 test_construction_teardown (PerformanceTest *test,
459 struct ConstructionTest *data = _data;
460 g_free (data->objects);
465 test_construction_print_result (PerformanceTest *test,
469 struct ConstructionTest *data = _data;
471 g_print ("Number of constructed objects per second: %.0f\n",
472 data->n_objects / time);
475 /*************************************************************
476 * Test runtime type check performance
477 *************************************************************/
479 #define NUM_KILO_CHECKS_PER_ROUND 50
481 struct TypeCheckTest {
487 test_type_check_setup (PerformanceTest *test)
489 struct TypeCheckTest *data;
491 data = g_new0 (struct TypeCheckTest, 1);
492 data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
498 test_type_check_init (PerformanceTest *test,
502 struct TypeCheckTest *data = _data;
504 data->n_checks = factor * NUM_KILO_CHECKS_PER_ROUND;
508 /* Work around g_type_check_instance_is_a being marked "pure",
509 and thus only called once for the loop. */
510 gboolean (*my_type_check_instance_is_a) (GTypeInstance *type_instance,
511 GType iface_type) = &g_type_check_instance_is_a;
514 test_type_check_run (PerformanceTest *test,
517 struct TypeCheckTest *data = _data;
518 volatile GObject *object = data->object;
519 volatile GType type, types[5];
522 types[0] = test_iface1_get_type ();
523 types[1] = test_iface2_get_type ();
524 types[2] = test_iface3_get_type ();
525 types[3] = test_iface4_get_type ();
526 types[4] = test_iface5_get_type ();
528 for (i = 0; i < data->n_checks; i++)
531 for (j = 0; j < 1000; j++)
533 my_type_check_instance_is_a ((GTypeInstance *)object,
540 test_type_check_finish (PerformanceTest *test,
546 test_type_check_print_result (PerformanceTest *test,
550 struct TypeCheckTest *data = _data;
551 g_print ("Million type checks per second: %.2f\n",
552 data->n_checks / (1000*time));
556 test_type_check_teardown (PerformanceTest *test,
559 struct TypeCheckTest *data = _data;
561 g_object_unref (data->object);
565 /*************************************************************
566 * Test signal emissions performance
567 *************************************************************/
569 #define NUM_EMISSIONS_PER_ROUND 10000
571 struct EmissionTest {
576 test_emission_setup (PerformanceTest *test)
578 struct EmissionTest *data;
580 data = g_new0 (struct EmissionTest, 1);
581 data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
587 test_emission_init (PerformanceTest *test,
591 struct EmissionTest *data = _data;
593 data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
597 test_emission_run (PerformanceTest *test,
600 struct EmissionTest *data = _data;
601 GObject *object = data->object;
604 for (i = 0; i < data->n_checks; i++)
605 g_signal_emit (object,
606 complex_signals[COMPLEX_SIGNAL],
611 test_emission_finish (PerformanceTest *test,
617 test_emission_print_result (PerformanceTest *test,
621 struct EmissionTest *data = _data;
623 g_print ("Emissions per second: %.0f\n",
624 data->n_checks / time);
628 test_emission_teardown (PerformanceTest *test,
631 struct EmissionTest *data = _data;
633 g_object_unref (data->object);
639 /*************************************************************
641 *************************************************************/
643 static PerformanceTest tests[] = {
645 "simple-construction",
646 simple_object_get_type,
647 test_construction_setup,
648 test_construction_init,
649 test_construction_run,
650 test_construction_finish,
651 test_construction_teardown,
652 test_construction_print_result
655 "complex-construction",
656 complex_object_get_type,
657 test_construction_setup,
658 test_construction_init,
659 test_construction_run,
660 test_construction_finish,
661 test_construction_teardown,
662 test_construction_print_result
667 test_type_check_setup,
668 test_type_check_init,
670 test_type_check_finish,
671 test_type_check_teardown,
672 test_type_check_print_result
680 test_emission_finish,
681 test_emission_teardown,
682 test_emission_print_result
686 static PerformanceTest *
687 find_test (const char *name)
690 for (i = 0; i < G_N_ELEMENTS (tests); i++)
692 if (strcmp (tests[i].name, name) == 0)
701 PerformanceTest *test;
702 GOptionContext *context;
703 GError *error = NULL;
708 context = g_option_context_new ("GObject performance tests");
709 g_option_context_add_main_entries (context, cmd_entries, NULL);
710 if (!g_option_context_parse (context, &argc, &argv, &error))
712 g_printerr ("%s: %s\n", argv[0], error->message);
717 g_thread_init (NULL);
721 for (i = 1; i < argc; i++)
723 test = find_test (argv[i]);
730 for (i = 0; i < G_N_ELEMENTS (tests); i++)
731 run_test (&tests[i]);