Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * Copyright (C) 2009 Red Hat, Inc.
3 : : * Copyright (C) 2022 Canonical Ltd.
4 : : *
5 : : * This library is free software; you can redistribute it and/or
6 : : * modify it under the terms of the GNU Lesser General Public
7 : : * License as published by the Free Software Foundation; either
8 : : * version 2.1 of the License, or (at your option) any later version.
9 : : *
10 : : * This library is distributed in the hope that it will be useful,
11 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : : * Lesser General Public License for more details.
14 : : *
15 : : * You should have received a copy of the GNU Lesser General
16 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 : : */
18 : :
19 : : #include <math.h>
20 : : #include <string.h>
21 : : #include <glib-object.h>
22 : : #include "../testcommon.h"
23 : :
24 : : #define WARM_UP_N_RUNS 50
25 : : #define WARM_UP_ALWAYS_SEC 2.0
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 : : * enough that the risk of any random slowness will miss the
31 : : * running window */
32 : : #define TARGET_ROUND_TIME 0.008
33 : :
34 : : static gboolean verbose = FALSE;
35 : : static gboolean quiet = FALSE;
36 : : static int test_length = DEFAULT_TEST_TIME;
37 : : static double test_factor = 0;
38 : : static GTimer *global_timer = NULL;
39 : :
40 : : static GOptionEntry cmd_entries[] = {
41 : : {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
42 : : "Print extra information", NULL},
43 : : {"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
44 : : "Print extra information", NULL},
45 : : {"seconds", 's', 0, G_OPTION_ARG_INT, &test_length,
46 : : "Time to run each test in seconds", NULL},
47 : : {"factor", 'f', 0, G_OPTION_ARG_DOUBLE, &test_factor,
48 : : "Use a fixed factor for sample runs (also $GLIB_PERFORMANCE_FACTOR)", NULL},
49 : : G_OPTION_ENTRY_NULL
50 : : };
51 : :
52 : : typedef struct _PerformanceTest PerformanceTest;
53 : : struct _PerformanceTest {
54 : : const char *name;
55 : : gpointer extra_data;
56 : :
57 : : gpointer (*setup) (PerformanceTest *test);
58 : : void (*init) (PerformanceTest *test,
59 : : gpointer data,
60 : : double factor);
61 : : void (*run) (PerformanceTest *test,
62 : : gpointer data);
63 : : void (*finish) (PerformanceTest *test,
64 : : gpointer data);
65 : : void (*teardown) (PerformanceTest *test,
66 : : gpointer data);
67 : : void (*print_result) (PerformanceTest *test,
68 : : gpointer data,
69 : : double time);
70 : : };
71 : :
72 : : static void
73 : 26 : run_test (PerformanceTest *test)
74 : : {
75 : 26 : gpointer data = NULL;
76 : : guint64 i, num_rounds;
77 : : double elapsed, min_elapsed, max_elapsed, avg_elapsed, factor;
78 : : GTimer *timer;
79 : :
80 : 26 : if (verbose || !quiet)
81 : 26 : g_print ("Running test %s\n", test->name);
82 : :
83 : : /* Set up test */
84 : 26 : timer = g_timer_new ();
85 : 26 : data = test->setup (test);
86 : :
87 : 26 : if (verbose)
88 : 0 : g_print ("Warming up\n");
89 : :
90 : 26 : g_timer_start (timer);
91 : :
92 : : /* Warm up the test by doing a few runs */
93 : 90 : for (i = 0; TRUE; i++)
94 : : {
95 : 90 : test->init (test, data, 1.0);
96 : 90 : test->run (test, data);
97 : 90 : test->finish (test, data);
98 : :
99 : 90 : if (test_factor > 0)
100 : : {
101 : : /* The caller specified a constant factor. That makes mostly
102 : : * sense, to ensure that the test run is independent from
103 : : * external factors. In this case, don't make warm up dependent
104 : : * on WARM_UP_ALWAYS_SEC. */
105 : : }
106 : 90 : else if (global_timer)
107 : : {
108 : 65 : if (g_timer_elapsed (global_timer, NULL) < WARM_UP_ALWAYS_SEC)
109 : : {
110 : : /* We always warm up for a certain time where we keep the
111 : : * CPU busy.
112 : : *
113 : : * Note that when we run multiple tests, then this is only
114 : : * performed once for the first test. */
115 : 64 : continue;
116 : : }
117 : 1 : g_clear_pointer (&global_timer, g_timer_destroy);
118 : : }
119 : :
120 : 26 : if (i >= WARM_UP_N_RUNS)
121 : 1 : break;
122 : :
123 : 25 : if (test_factor == 0 && g_timer_elapsed (timer, NULL) > test_length / 10)
124 : : {
125 : : /* The warm up should not take longer than 10 % of the entire
126 : : * test run. Note that the warm up time for WARM_UP_ALWAYS_SEC
127 : : * already passed. */
128 : 25 : break;
129 : : }
130 : : }
131 : :
132 : 26 : g_timer_stop (timer);
133 : 26 : elapsed = g_timer_elapsed (timer, NULL);
134 : :
135 : 26 : if (verbose)
136 : : {
137 : 0 : g_print ("Warm up time: %.2f secs\n", elapsed);
138 : 0 : g_print ("Estimating round time\n");
139 : : }
140 : :
141 : 26 : min_elapsed = 0;
142 : :
143 : 26 : if (test_factor > 0)
144 : : {
145 : 0 : factor = test_factor;
146 : : }
147 : : else
148 : : {
149 : : /* Estimate time for one run by doing a few test rounds. */
150 : 156 : for (i = 0; i < ESTIMATE_ROUND_TIME_N_RUNS; i++)
151 : : {
152 : 130 : test->init (test, data, 1.0);
153 : 130 : g_timer_start (timer);
154 : 130 : test->run (test, data);
155 : 130 : g_timer_stop (timer);
156 : 130 : test->finish (test, data);
157 : :
158 : 130 : elapsed = g_timer_elapsed (timer, NULL);
159 : 130 : if (i == 0)
160 : 26 : min_elapsed = elapsed;
161 : : else
162 : 104 : min_elapsed = MIN (min_elapsed, elapsed);
163 : : }
164 : :
165 : 26 : factor = TARGET_ROUND_TIME / min_elapsed;
166 : : }
167 : :
168 : 26 : if (verbose)
169 : 0 : g_print ("Uncorrected round time: %.4f msecs, correction factor %.2f\n", 1000*min_elapsed, factor);
170 : :
171 : : /* Calculate number of rounds needed */
172 : 26 : num_rounds = (guint64) (test_length / TARGET_ROUND_TIME) + 1;
173 : :
174 : 26 : if (verbose)
175 : 0 : g_print ("Running %"G_GINT64_MODIFIER"d rounds\n", num_rounds);
176 : :
177 : : /* Run the test */
178 : 26 : avg_elapsed = 0.0;
179 : 26 : min_elapsed = 1e100;
180 : 26 : max_elapsed = 0.0;
181 : 52 : for (i = 0; i < num_rounds; i++)
182 : : {
183 : 26 : test->init (test, data, factor);
184 : 26 : g_timer_start (timer);
185 : 26 : test->run (test, data);
186 : 26 : g_timer_stop (timer);
187 : 26 : test->finish (test, data);
188 : :
189 : 26 : if (i < num_rounds / 20)
190 : : {
191 : : /* The first 5% are additional warm up. Ignore. */
192 : 0 : continue;
193 : : }
194 : :
195 : 26 : elapsed = g_timer_elapsed (timer, NULL);
196 : :
197 : 26 : min_elapsed = MIN (min_elapsed, elapsed);
198 : 26 : max_elapsed = MAX (max_elapsed, elapsed);
199 : 26 : avg_elapsed += elapsed;
200 : : }
201 : :
202 : 26 : if (num_rounds > 1)
203 : 0 : avg_elapsed = avg_elapsed / num_rounds;
204 : :
205 : 26 : if (verbose)
206 : : {
207 : 0 : g_print ("Minimum corrected round time: %.2f msecs\n", min_elapsed * 1000);
208 : 0 : g_print ("Maximum corrected round time: %.2f msecs\n", max_elapsed * 1000);
209 : 0 : g_print ("Average corrected round time: %.2f msecs\n", avg_elapsed * 1000);
210 : : }
211 : :
212 : : /* Print the results */
213 : 26 : g_print ("%s: ", test->name);
214 : 26 : test->print_result (test, data, min_elapsed);
215 : :
216 : : /* Tear down */
217 : 26 : test->teardown (test, data);
218 : 26 : g_timer_destroy (timer);
219 : 26 : }
220 : :
221 : : /*************************************************************
222 : : * Simple object is a very simple small GObject subclass
223 : : * with no properties, no signals, implementing no interfaces
224 : : *************************************************************/
225 : :
226 : : static GType simple_object_get_type (void);
227 : : #define SIMPLE_TYPE_OBJECT (simple_object_get_type ())
228 : : typedef struct _SimpleObject SimpleObject;
229 : : typedef struct _SimpleObjectClass SimpleObjectClass;
230 : :
231 : : struct _SimpleObject
232 : : {
233 : : GObject parent_instance;
234 : : int val;
235 : : };
236 : :
237 : : struct _SimpleObjectClass
238 : : {
239 : : GObjectClass parent_class;
240 : : };
241 : :
242 : 5 : G_DEFINE_TYPE (SimpleObject, simple_object, G_TYPE_OBJECT)
243 : :
244 : : static void
245 : 779967 : simple_object_finalize (GObject *object)
246 : : {
247 : 779967 : G_OBJECT_CLASS (simple_object_parent_class)->finalize (object);
248 : 779967 : }
249 : :
250 : : static void
251 : 1 : simple_object_class_init (SimpleObjectClass *class)
252 : : {
253 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (class);
254 : :
255 : 1 : object_class->finalize = simple_object_finalize;
256 : 1 : }
257 : :
258 : : static void
259 : 779967 : simple_object_init (SimpleObject *simple_object)
260 : : {
261 : 779967 : simple_object->val = 42;
262 : 779967 : }
263 : :
264 : : typedef struct _TestIfaceClass TestIfaceClass;
265 : : typedef struct _TestIfaceClass TestIface1Class;
266 : : typedef struct _TestIfaceClass TestIface2Class;
267 : : typedef struct _TestIfaceClass TestIface3Class;
268 : : typedef struct _TestIfaceClass TestIface4Class;
269 : : typedef struct _TestIfaceClass TestIface5Class;
270 : : typedef struct _TestIface TestIface;
271 : :
272 : : struct _TestIfaceClass
273 : : {
274 : : GTypeInterface base_iface;
275 : : void (*method) (TestIface *obj);
276 : : };
277 : :
278 : : static GType test_iface1_get_type (void);
279 : : static GType test_iface2_get_type (void);
280 : : static GType test_iface3_get_type (void);
281 : : static GType test_iface4_get_type (void);
282 : : static GType test_iface5_get_type (void);
283 : :
284 : : #define TEST_TYPE_IFACE1 (test_iface1_get_type ())
285 : : #define TEST_TYPE_IFACE2 (test_iface2_get_type ())
286 : : #define TEST_TYPE_IFACE3 (test_iface3_get_type ())
287 : : #define TEST_TYPE_IFACE4 (test_iface4_get_type ())
288 : : #define TEST_TYPE_IFACE5 (test_iface5_get_type ())
289 : :
290 : 8 : static DEFINE_IFACE (TestIface1, test_iface1, NULL, NULL)
291 : 8 : static DEFINE_IFACE (TestIface2, test_iface2, NULL, NULL)
292 : 8 : static DEFINE_IFACE (TestIface3, test_iface3, NULL, NULL)
293 : 8 : static DEFINE_IFACE (TestIface4, test_iface4, NULL, NULL)
294 : 8 : static DEFINE_IFACE (TestIface5, test_iface5, NULL, NULL)
295 : :
296 : : /*************************************************************
297 : : * Complex object is a GObject subclass with a properties,
298 : : * construct properties, signals and implementing an interface.
299 : : *************************************************************/
300 : :
301 : : static GType complex_object_get_type (void);
302 : : #define COMPLEX_TYPE_OBJECT (complex_object_get_type ())
303 : : typedef struct _ComplexObject ComplexObject;
304 : : typedef struct _ComplexObjectClass ComplexObjectClass;
305 : :
306 : : struct _ComplexObject
307 : : {
308 : : GObject parent_instance;
309 : : int val1;
310 : : char *val2;
311 : : };
312 : :
313 : : struct _ComplexObjectClass
314 : : {
315 : : GObjectClass parent_class;
316 : :
317 : : void (*signal) (ComplexObject *obj);
318 : : void (*signal_empty) (ComplexObject *obj);
319 : : };
320 : :
321 : : static void complex_test_iface_init (gpointer g_iface,
322 : : gpointer iface_data);
323 : :
324 : 590604 : G_DEFINE_TYPE_EXTENDED (ComplexObject, complex_object,
325 : : G_TYPE_OBJECT, 0,
326 : : G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE1, complex_test_iface_init)
327 : : G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE2, complex_test_iface_init)
328 : : G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE3, complex_test_iface_init)
329 : : G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE4, complex_test_iface_init)
330 : : G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE5, complex_test_iface_init))
331 : :
332 : : #define COMPLEX_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), COMPLEX_TYPE_OBJECT, ComplexObject))
333 : :
334 : : enum {
335 : : PROP_0,
336 : : PROP_VAL1,
337 : : PROP_VAL2,
338 : : N_PROPERTIES
339 : : };
340 : :
341 : : static GParamSpec *pspecs[N_PROPERTIES] = { NULL, };
342 : :
343 : : enum {
344 : : COMPLEX_SIGNAL,
345 : : COMPLEX_SIGNAL_EMPTY,
346 : : COMPLEX_SIGNAL_GENERIC,
347 : : COMPLEX_SIGNAL_GENERIC_EMPTY,
348 : : COMPLEX_SIGNAL_ARGS,
349 : : COMPLEX_LAST_SIGNAL
350 : : };
351 : :
352 : : static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
353 : :
354 : : static void
355 : 200049 : complex_object_finalize (GObject *object)
356 : : {
357 : 200049 : ComplexObject *c = COMPLEX_OBJECT (object);
358 : :
359 : 200049 : g_free (c->val2);
360 : :
361 : 200049 : G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
362 : 200049 : }
363 : :
364 : : static void
365 : 327326 : complex_object_set_property (GObject *object,
366 : : guint prop_id,
367 : : const GValue *value,
368 : : GParamSpec *pspec)
369 : : {
370 : 327326 : ComplexObject *complex = COMPLEX_OBJECT (object);
371 : :
372 : 327326 : switch (prop_id)
373 : : {
374 : 262879 : case PROP_VAL1:
375 : 262879 : complex->val1 = g_value_get_int (value);
376 : 262879 : break;
377 : 64447 : case PROP_VAL2:
378 : 64447 : g_free (complex->val2);
379 : 64447 : complex->val2 = g_value_dup_string (value);
380 : 64447 : break;
381 : 0 : default:
382 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
383 : 0 : break;
384 : : }
385 : 327326 : }
386 : :
387 : : static void
388 : 63204 : complex_object_get_property (GObject *object,
389 : : guint prop_id,
390 : : GValue *value,
391 : : GParamSpec *pspec)
392 : : {
393 : 63204 : ComplexObject *complex = COMPLEX_OBJECT (object);
394 : :
395 : 63204 : switch (prop_id)
396 : : {
397 : 63204 : case PROP_VAL1:
398 : 63204 : g_value_set_int (value, complex->val1);
399 : 63204 : break;
400 : 0 : case PROP_VAL2:
401 : 0 : g_value_set_string (value, complex->val2);
402 : 0 : break;
403 : 0 : default:
404 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
405 : 0 : break;
406 : : }
407 : 63204 : }
408 : :
409 : : static void
410 : 376901 : complex_object_real_signal (ComplexObject *obj)
411 : : {
412 : 376901 : }
413 : :
414 : : static void
415 : 1 : complex_object_class_init (ComplexObjectClass *class)
416 : : {
417 : 1 : GObjectClass *object_class = G_OBJECT_CLASS (class);
418 : :
419 : 1 : object_class->finalize = complex_object_finalize;
420 : 1 : object_class->set_property = complex_object_set_property;
421 : 1 : object_class->get_property = complex_object_get_property;
422 : :
423 : 1 : class->signal = complex_object_real_signal;
424 : :
425 : 1 : complex_signals[COMPLEX_SIGNAL] =
426 : 1 : g_signal_new ("signal",
427 : : G_TYPE_FROM_CLASS (object_class),
428 : : G_SIGNAL_RUN_FIRST,
429 : : G_STRUCT_OFFSET (ComplexObjectClass, signal),
430 : : NULL, NULL,
431 : : g_cclosure_marshal_VOID__VOID,
432 : : G_TYPE_NONE, 0);
433 : :
434 : 1 : complex_signals[COMPLEX_SIGNAL_EMPTY] =
435 : 1 : g_signal_new ("signal-empty",
436 : : G_TYPE_FROM_CLASS (object_class),
437 : : G_SIGNAL_RUN_FIRST,
438 : : G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
439 : : NULL, NULL,
440 : : g_cclosure_marshal_VOID__VOID,
441 : : G_TYPE_NONE, 0);
442 : :
443 : 1 : complex_signals[COMPLEX_SIGNAL_GENERIC] =
444 : 1 : g_signal_new ("signal-generic",
445 : : G_TYPE_FROM_CLASS (object_class),
446 : : G_SIGNAL_RUN_FIRST,
447 : : G_STRUCT_OFFSET (ComplexObjectClass, signal),
448 : : NULL, NULL,
449 : : NULL,
450 : : G_TYPE_NONE, 0);
451 : 1 : complex_signals[COMPLEX_SIGNAL_GENERIC_EMPTY] =
452 : 1 : g_signal_new ("signal-generic-empty",
453 : : G_TYPE_FROM_CLASS (object_class),
454 : : G_SIGNAL_RUN_FIRST,
455 : : G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
456 : : NULL, NULL,
457 : : NULL,
458 : : G_TYPE_NONE, 0);
459 : :
460 : 1 : complex_signals[COMPLEX_SIGNAL_ARGS] =
461 : 1 : g_signal_new ("signal-args",
462 : : G_TYPE_FROM_CLASS (object_class),
463 : : G_SIGNAL_RUN_FIRST,
464 : : G_STRUCT_OFFSET (ComplexObjectClass, signal),
465 : : NULL, NULL,
466 : : g_cclosure_marshal_VOID__UINT_POINTER,
467 : : G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
468 : :
469 : 1 : pspecs[PROP_VAL1] = g_param_spec_int ("val1", "val1", "val1",
470 : : 0, G_MAXINT, 42,
471 : : G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
472 : 1 : pspecs[PROP_VAL2] = g_param_spec_string ("val2", "val2", "val2",
473 : : NULL,
474 : : G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
475 : :
476 : 1 : g_object_class_install_properties (object_class, N_PROPERTIES, pspecs);
477 : 1 : }
478 : :
479 : : static void
480 : 0 : complex_object_iface_method (TestIface *obj)
481 : : {
482 : 0 : ComplexObject *complex = COMPLEX_OBJECT (obj);
483 : 0 : complex->val1++;
484 : 0 : }
485 : :
486 : : static void
487 : 5 : complex_test_iface_init (gpointer g_iface,
488 : : gpointer iface_data)
489 : : {
490 : 5 : TestIfaceClass *iface = g_iface;
491 : 5 : iface->method = complex_object_iface_method;
492 : 5 : }
493 : :
494 : : static void
495 : 200049 : complex_object_init (ComplexObject *complex_object)
496 : : {
497 : 200049 : complex_object->val1 = 42;
498 : 200049 : }
499 : :
500 : : /*************************************************************
501 : : * Test object construction performance
502 : : *************************************************************/
503 : :
504 : : #define NUM_OBJECT_TO_CONSTRUCT 10000
505 : :
506 : : struct ConstructionTest {
507 : : GObject **objects;
508 : : unsigned int n_objects;
509 : : GType type;
510 : : };
511 : :
512 : : static gpointer
513 : 6 : test_construction_setup (PerformanceTest *test)
514 : : {
515 : : struct ConstructionTest *data;
516 : :
517 : 6 : data = g_new0 (struct ConstructionTest, 1);
518 : 6 : data->type = ((GType (*)(void))test->extra_data)();
519 : :
520 : 6 : return data;
521 : : }
522 : :
523 : : static void
524 : 99 : test_construction_init (PerformanceTest *test,
525 : : gpointer _data,
526 : : double count_factor)
527 : : {
528 : 99 : struct ConstructionTest *data = _data;
529 : : unsigned int n;
530 : :
531 : 99 : n = (unsigned int) (NUM_OBJECT_TO_CONSTRUCT * count_factor);
532 : 99 : if (data->n_objects != n)
533 : : {
534 : 10 : data->n_objects = n;
535 : 10 : data->objects = g_renew (GObject *, data->objects, n);
536 : : }
537 : 99 : }
538 : :
539 : : static void
540 : 71 : test_construction_run (PerformanceTest *test,
541 : : gpointer _data)
542 : : {
543 : 71 : struct ConstructionTest *data = _data;
544 : 71 : GObject **objects = data->objects;
545 : 71 : GType type = data->type;
546 : : unsigned int n_objects;
547 : :
548 : 71 : n_objects = data->n_objects;
549 : 716720 : for (unsigned int i = 0; i < n_objects; i++)
550 : 716649 : objects[i] = g_object_new (type, NULL);
551 : 71 : }
552 : :
553 : : static void
554 : 7 : test_construction_run1 (PerformanceTest *test,
555 : : gpointer _data)
556 : : {
557 : 7 : struct ConstructionTest *data = _data;
558 : 7 : GObject **objects = data->objects;
559 : : unsigned int n_objects;
560 : :
561 : 7 : n_objects = data->n_objects;
562 : 158046 : for (unsigned int i = 0; i < n_objects; i++)
563 : 158039 : objects[i] = (GObject *) g_slice_new0 (SimpleObject);
564 : 7 : }
565 : :
566 : : static void
567 : 7 : test_complex_construction_run (PerformanceTest *test,
568 : : gpointer _data)
569 : : {
570 : 7 : struct ConstructionTest *data = _data;
571 : 7 : GObject **objects = data->objects;
572 : 7 : GType type = data->type;
573 : : unsigned int n_objects;
574 : :
575 : 7 : n_objects = data->n_objects;
576 : 64454 : for (unsigned int i = 0; i < n_objects; i++)
577 : 64447 : objects[i] = g_object_new (type, "val1", 5, "val2", "thousand", NULL);
578 : 7 : }
579 : :
580 : : static void
581 : 7 : test_complex_construction_run1 (PerformanceTest *test,
582 : : gpointer _data)
583 : : {
584 : 7 : struct ConstructionTest *data = _data;
585 : 7 : GObject **objects = data->objects;
586 : 7 : GType type = data->type;
587 : : unsigned int n_objects;
588 : :
589 : 7 : n_objects = data->n_objects;
590 : 67609 : for (unsigned int i = 0; i < n_objects; i++)
591 : : {
592 : : ComplexObject *object;
593 : 67602 : object = (ComplexObject *)g_object_new (type, NULL);
594 : 67602 : object->val1 = 5;
595 : 67602 : object->val2 = g_strdup ("thousand");
596 : 67602 : objects[i] = (GObject *)object;
597 : : }
598 : 7 : }
599 : :
600 : : static void
601 : 7 : test_complex_construction_run2 (PerformanceTest *test,
602 : : gpointer _data)
603 : : {
604 : 7 : struct ConstructionTest *data = _data;
605 : 7 : GObject **objects = data->objects;
606 : 7 : GType type = data->type;
607 : : unsigned int n_objects;
608 : :
609 : 7 : n_objects = data->n_objects;
610 : 67987 : for (unsigned int i = 0; i < n_objects; i++)
611 : : {
612 : 67980 : objects[i] = g_object_new (type, NULL);
613 : : }
614 : 7 : }
615 : :
616 : : static void
617 : 92 : test_construction_finish (PerformanceTest *test,
618 : : gpointer _data)
619 : : {
620 : 92 : struct ConstructionTest *data = _data;
621 : :
622 : 916770 : for (unsigned int i = 0; i < data->n_objects; i++)
623 : 916678 : g_object_unref (data->objects[i]);
624 : 92 : }
625 : :
626 : : static void
627 : 7 : test_construction_finish1 (PerformanceTest *test,
628 : : gpointer _data)
629 : : {
630 : 7 : struct ConstructionTest *data = _data;
631 : :
632 : 158046 : for (unsigned int i = 0; i < data->n_objects; i++)
633 : 158039 : g_slice_free (SimpleObject, (SimpleObject *)data->objects[i]);
634 : 7 : }
635 : :
636 : : static void
637 : 6 : test_construction_teardown (PerformanceTest *test,
638 : : gpointer _data)
639 : : {
640 : 6 : struct ConstructionTest *data = _data;
641 : 6 : g_free (data->objects);
642 : 6 : g_free (data);
643 : 6 : }
644 : :
645 : : static void
646 : 7 : test_finalization_init (PerformanceTest *test,
647 : : gpointer _data,
648 : : double count_factor)
649 : : {
650 : 7 : struct ConstructionTest *data = _data;
651 : : unsigned int n;
652 : :
653 : 7 : n = (unsigned int) (NUM_OBJECT_TO_CONSTRUCT * count_factor);
654 : 7 : if (data->n_objects != n)
655 : : {
656 : 2 : data->n_objects = n;
657 : 2 : data->objects = g_renew (GObject *, data->objects, n);
658 : : }
659 : :
660 : 63325 : for (unsigned int i = 0; i < data->n_objects; i++)
661 : : {
662 : 63318 : data->objects[i] = g_object_new (data->type, NULL);
663 : : }
664 : 7 : }
665 : :
666 : : static void
667 : 7 : test_finalization_run (PerformanceTest *test,
668 : : gpointer _data)
669 : : {
670 : 7 : struct ConstructionTest *data = _data;
671 : 7 : GObject **objects = data->objects;
672 : : unsigned int n_objects;
673 : :
674 : 7 : n_objects = data->n_objects;
675 : 63325 : for (unsigned int i = 0; i < n_objects; i++)
676 : : {
677 : 63318 : g_object_unref (objects[i]);
678 : : }
679 : 7 : }
680 : :
681 : : static void
682 : 7 : test_finalization_finish (PerformanceTest *test,
683 : : gpointer _data)
684 : : {
685 : 7 : }
686 : :
687 : : static void
688 : 5 : test_construction_print_result (PerformanceTest *test,
689 : : gpointer _data,
690 : : double time)
691 : : {
692 : 5 : struct ConstructionTest *data = _data;
693 : :
694 : 5 : g_print ("Millions of constructed objects per second: %.3f\n",
695 : 5 : data->n_objects / (time * 1000000));
696 : 5 : }
697 : :
698 : : static void
699 : 1 : test_finalization_print_result (PerformanceTest *test,
700 : : gpointer _data,
701 : : double time)
702 : : {
703 : 1 : struct ConstructionTest *data = _data;
704 : :
705 : 1 : g_print ("Millions of finalized objects per second: %.3f\n",
706 : 1 : data->n_objects / (time * 1000000));
707 : 1 : }
708 : :
709 : : /*************************************************************
710 : : * Test runtime type check performance
711 : : *************************************************************/
712 : :
713 : : #define NUM_KILO_CHECKS_PER_ROUND 50
714 : :
715 : : struct TypeCheckTest {
716 : : GObject *object;
717 : : unsigned int n_checks;
718 : : };
719 : :
720 : : static gpointer
721 : 1 : test_type_check_setup (PerformanceTest *test)
722 : : {
723 : : struct TypeCheckTest *data;
724 : :
725 : 1 : data = g_new0 (struct TypeCheckTest, 1);
726 : 1 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
727 : :
728 : 1 : return data;
729 : : }
730 : :
731 : : static void
732 : 7 : test_type_check_init (PerformanceTest *test,
733 : : gpointer _data,
734 : : double factor)
735 : : {
736 : 7 : struct TypeCheckTest *data = _data;
737 : :
738 : 7 : data->n_checks = (unsigned int) (factor * NUM_KILO_CHECKS_PER_ROUND);
739 : 7 : }
740 : :
741 : :
742 : : /* Work around g_type_check_instance_is_a being marked "pure",
743 : : and thus only called once for the loop. */
744 : : gboolean (*my_type_check_instance_is_a) (GTypeInstance *type_instance,
745 : : GType iface_type) = &g_type_check_instance_is_a;
746 : :
747 : : static void
748 : 7 : test_type_check_run (PerformanceTest *test,
749 : : gpointer _data)
750 : : {
751 : 7 : struct TypeCheckTest *data = _data;
752 : 7 : GObject *object = data->object;
753 : : GType type, types[5];
754 : :
755 : 7 : types[0] = test_iface1_get_type ();
756 : 7 : types[1] = test_iface2_get_type ();
757 : 7 : types[2] = test_iface3_get_type ();
758 : 7 : types[3] = test_iface4_get_type ();
759 : 7 : types[4] = test_iface5_get_type ();
760 : :
761 : 341 : for (unsigned int i = 0; i < data->n_checks; i++)
762 : : {
763 : 334 : type = types[i%5];
764 : 334334 : for (unsigned int j = 0; j < 1000; j++)
765 : : {
766 : 334000 : my_type_check_instance_is_a ((GTypeInstance *)object,
767 : : type);
768 : : }
769 : : }
770 : 7 : }
771 : :
772 : : static void
773 : 7 : test_type_check_finish (PerformanceTest *test,
774 : : gpointer data)
775 : : {
776 : 7 : }
777 : :
778 : : static void
779 : 1 : test_type_check_print_result (PerformanceTest *test,
780 : : gpointer _data,
781 : : double time)
782 : : {
783 : 1 : struct TypeCheckTest *data = _data;
784 : 1 : g_print ("Million type checks per second: %.2f\n",
785 : 1 : data->n_checks / (1000*time));
786 : 1 : }
787 : :
788 : : static void
789 : 1 : test_type_check_teardown (PerformanceTest *test,
790 : : gpointer _data)
791 : : {
792 : 1 : struct TypeCheckTest *data = _data;
793 : :
794 : 1 : g_object_unref (data->object);
795 : 1 : g_free (data);
796 : 1 : }
797 : :
798 : : /*************************************************************
799 : : * Test signal emissions performance (common code)
800 : : *************************************************************/
801 : :
802 : : #define NUM_EMISSIONS_PER_ROUND 10000
803 : :
804 : : struct EmissionTest {
805 : : GObject *object;
806 : : unsigned int n_checks;
807 : : unsigned int signal_id;
808 : : };
809 : :
810 : : static void
811 : 56 : test_emission_run (PerformanceTest *test,
812 : : gpointer _data)
813 : : {
814 : 56 : struct EmissionTest *data = _data;
815 : 56 : GObject *object = data->object;
816 : :
817 : 545346 : for (unsigned int i = 0; i < data->n_checks; i++)
818 : 545290 : g_signal_emit (object, data->signal_id, 0);
819 : 56 : }
820 : :
821 : : static void
822 : 14 : test_emission_run_args (PerformanceTest *test,
823 : : gpointer _data)
824 : : {
825 : 14 : struct EmissionTest *data = _data;
826 : 14 : GObject *object = data->object;
827 : :
828 : 124347 : for (unsigned int i = 0; i < data->n_checks; i++)
829 : 124333 : g_signal_emit (object, data->signal_id, 0, 0, NULL);
830 : 14 : }
831 : :
832 : : /*************************************************************
833 : : * Test signal unhandled emissions performance
834 : : *************************************************************/
835 : :
836 : : static gpointer
837 : 5 : test_emission_unhandled_setup (PerformanceTest *test)
838 : : {
839 : : struct EmissionTest *data;
840 : :
841 : 5 : data = g_new0 (struct EmissionTest, 1);
842 : 5 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
843 : 5 : data->signal_id = complex_signals[GPOINTER_TO_UINT (test->extra_data)];
844 : 5 : return data;
845 : : }
846 : :
847 : : static void
848 : 35 : test_emission_unhandled_init (PerformanceTest *test,
849 : : gpointer _data,
850 : : double factor)
851 : : {
852 : 35 : struct EmissionTest *data = _data;
853 : :
854 : 35 : data->n_checks = (unsigned int) (factor * NUM_EMISSIONS_PER_ROUND);
855 : 35 : }
856 : :
857 : : static void
858 : 35 : test_emission_unhandled_finish (PerformanceTest *test,
859 : : gpointer data)
860 : : {
861 : 35 : }
862 : :
863 : : static void
864 : 5 : test_emission_unhandled_print_result (PerformanceTest *test,
865 : : gpointer _data,
866 : : double time)
867 : : {
868 : 5 : struct EmissionTest *data = _data;
869 : :
870 : 5 : g_print ("Emissions per second: %.0f\n",
871 : 5 : data->n_checks / time);
872 : 5 : }
873 : :
874 : : static void
875 : 5 : test_emission_unhandled_teardown (PerformanceTest *test,
876 : : gpointer _data)
877 : : {
878 : 5 : struct EmissionTest *data = _data;
879 : :
880 : 5 : g_object_unref (data->object);
881 : 5 : g_free (data);
882 : 5 : }
883 : :
884 : : /*************************************************************
885 : : * Test signal handled emissions performance
886 : : *************************************************************/
887 : :
888 : : static void
889 : 312798 : test_emission_handled_handler (ComplexObject *obj, gpointer data)
890 : : {
891 : 312798 : }
892 : :
893 : : static gpointer
894 : 5 : test_emission_handled_setup (PerformanceTest *test)
895 : : {
896 : : struct EmissionTest *data;
897 : :
898 : 5 : data = g_new0 (struct EmissionTest, 1);
899 : 5 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
900 : 5 : data->signal_id = complex_signals[GPOINTER_TO_UINT (test->extra_data)];
901 : 5 : g_signal_connect (data->object, "signal",
902 : : G_CALLBACK (test_emission_handled_handler),
903 : : NULL);
904 : 5 : g_signal_connect (data->object, "signal-empty",
905 : : G_CALLBACK (test_emission_handled_handler),
906 : : NULL);
907 : 5 : g_signal_connect (data->object, "signal-generic",
908 : : G_CALLBACK (test_emission_handled_handler),
909 : : NULL);
910 : 5 : g_signal_connect (data->object, "signal-generic-empty",
911 : : G_CALLBACK (test_emission_handled_handler),
912 : : NULL);
913 : 5 : g_signal_connect (data->object, "signal-args",
914 : : G_CALLBACK (test_emission_handled_handler),
915 : : NULL);
916 : :
917 : 5 : return data;
918 : : }
919 : :
920 : : static void
921 : 35 : test_emission_handled_init (PerformanceTest *test,
922 : : gpointer _data,
923 : : double factor)
924 : : {
925 : 35 : struct EmissionTest *data = _data;
926 : :
927 : 35 : data->n_checks = (unsigned int) (factor * NUM_EMISSIONS_PER_ROUND);
928 : 35 : }
929 : :
930 : : static void
931 : 35 : test_emission_handled_finish (PerformanceTest *test,
932 : : gpointer data)
933 : : {
934 : 35 : }
935 : :
936 : : static void
937 : 5 : test_emission_handled_print_result (PerformanceTest *test,
938 : : gpointer _data,
939 : : double time)
940 : : {
941 : 5 : struct EmissionTest *data = _data;
942 : :
943 : 5 : g_print ("Emissions per second: %.0f\n",
944 : 5 : data->n_checks / time);
945 : 5 : }
946 : :
947 : : static void
948 : 5 : test_emission_handled_teardown (PerformanceTest *test,
949 : : gpointer _data)
950 : : {
951 : 5 : struct EmissionTest *data = _data;
952 : :
953 : 5 : g_object_unref (data->object);
954 : 5 : g_free (data);
955 : 5 : }
956 : :
957 : : /*************************************************************
958 : : * Test object notify performance (common code)
959 : : *************************************************************/
960 : :
961 : : #define NUM_NOTIFY_PER_ROUND 10000
962 : :
963 : : struct NotifyTest {
964 : : GObject *object;
965 : : unsigned int n_checks;
966 : : };
967 : :
968 : : static void
969 : 14 : test_notify_run (PerformanceTest *test,
970 : : void *_data)
971 : : {
972 : 14 : struct NotifyTest *data = _data;
973 : 14 : GObject *object = data->object;
974 : :
975 : 128380 : for (unsigned int i = 0; i < data->n_checks; i++)
976 : 128366 : g_object_notify (object, "val1");
977 : 14 : }
978 : :
979 : : static void
980 : 14 : test_notify_by_pspec_run (PerformanceTest *test,
981 : : void *_data)
982 : : {
983 : 14 : struct NotifyTest *data = _data;
984 : 14 : GObject *object = data->object;
985 : :
986 : 163718 : for (unsigned int i = 0; i < data->n_checks; i++)
987 : 163704 : g_object_notify_by_pspec (object, pspecs[PROP_VAL1]);
988 : 14 : }
989 : :
990 : : /*************************************************************
991 : : * Test notify unhandled performance
992 : : *************************************************************/
993 : :
994 : : static void *
995 : 2 : test_notify_unhandled_setup (PerformanceTest *test)
996 : : {
997 : : struct NotifyTest *data;
998 : :
999 : 2 : data = g_new0 (struct NotifyTest, 1);
1000 : 2 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1001 : 2 : return data;
1002 : : }
1003 : :
1004 : : static void
1005 : 14 : test_notify_unhandled_init (PerformanceTest *test,
1006 : : void *_data,
1007 : : double factor)
1008 : : {
1009 : 14 : struct NotifyTest *data = _data;
1010 : :
1011 : 14 : data->n_checks = (unsigned int) (factor * NUM_NOTIFY_PER_ROUND);
1012 : 14 : }
1013 : :
1014 : : static void
1015 : 14 : test_notify_unhandled_finish (PerformanceTest *test,
1016 : : void *data)
1017 : : {
1018 : 14 : }
1019 : :
1020 : : static void
1021 : 2 : test_notify_unhandled_print_result (PerformanceTest *test,
1022 : : void *_data,
1023 : : double time)
1024 : : {
1025 : 2 : struct NotifyTest *data = _data;
1026 : :
1027 : 2 : g_print ("Notify (unhandled) per second: %.0f\n",
1028 : 2 : data->n_checks / time);
1029 : 2 : }
1030 : :
1031 : : static void
1032 : 2 : test_notify_unhandled_teardown (PerformanceTest *test,
1033 : : void *_data)
1034 : : {
1035 : 2 : struct NotifyTest *data = _data;
1036 : :
1037 : 2 : g_object_unref (data->object);
1038 : 2 : g_free (data);
1039 : 2 : }
1040 : :
1041 : : /*************************************************************
1042 : : * Test notify handled performance
1043 : : *************************************************************/
1044 : :
1045 : : static void
1046 : 123109 : test_notify_handled_handler (ComplexObject *obj, GParamSpec *pspec, void *data)
1047 : : {
1048 : 123109 : }
1049 : :
1050 : : static void *
1051 : 2 : test_notify_handled_setup (PerformanceTest *test)
1052 : : {
1053 : : struct NotifyTest *data;
1054 : :
1055 : 2 : data = g_new0 (struct NotifyTest, 1);
1056 : 2 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1057 : :
1058 : 2 : g_signal_connect (data->object, "notify::val1",
1059 : : G_CALLBACK (test_notify_handled_handler), data);
1060 : 2 : g_signal_connect (data->object, "notify::val2",
1061 : : G_CALLBACK (test_notify_handled_handler), data);
1062 : :
1063 : 2 : return data;
1064 : : }
1065 : :
1066 : : static void
1067 : 14 : test_notify_handled_init (PerformanceTest *test,
1068 : : void *_data,
1069 : : double factor)
1070 : : {
1071 : 14 : struct NotifyTest *data = _data;
1072 : :
1073 : 14 : data->n_checks = (unsigned int) (factor * NUM_NOTIFY_PER_ROUND);
1074 : 14 : }
1075 : :
1076 : : static void
1077 : 14 : test_notify_handled_finish (PerformanceTest *test,
1078 : : void *data)
1079 : : {
1080 : 14 : }
1081 : :
1082 : : static void
1083 : 2 : test_notify_handled_print_result (PerformanceTest *test,
1084 : : void *_data,
1085 : : double time)
1086 : : {
1087 : 2 : struct NotifyTest *data = _data;
1088 : :
1089 : 2 : g_print ("Notify per second: %.0f\n",
1090 : 2 : data->n_checks / time);
1091 : 2 : }
1092 : :
1093 : : static void
1094 : 2 : test_notify_handled_teardown (PerformanceTest *test,
1095 : : void *_data)
1096 : : {
1097 : 2 : struct NotifyTest *data = _data;
1098 : :
1099 : 2 : g_assert_cmpuint (
1100 : : g_signal_handlers_disconnect_by_func (data->object,
1101 : : test_notify_handled_handler,
1102 : : data), ==, 2);
1103 : 2 : g_object_unref (data->object);
1104 : 2 : g_free (data);
1105 : 2 : }
1106 : :
1107 : : /*************************************************************
1108 : : * Test object set performance
1109 : : *************************************************************/
1110 : :
1111 : : #define NUM_SET_PER_ROUND 10000
1112 : :
1113 : : struct SetTest {
1114 : : GObject *object;
1115 : : unsigned int n_checks;
1116 : : };
1117 : :
1118 : : static void
1119 : 7 : test_set_run (PerformanceTest *test,
1120 : : void *_data)
1121 : : {
1122 : 7 : struct SetTest *data = _data;
1123 : 7 : GObject *object = data->object;
1124 : :
1125 : 62837 : for (unsigned int i = 0; i < data->n_checks; i++)
1126 : 62830 : g_object_set (object, "val1", i, NULL);
1127 : 7 : }
1128 : :
1129 : : static void *
1130 : 1 : test_set_setup (PerformanceTest *test)
1131 : : {
1132 : : struct SetTest *data;
1133 : :
1134 : 1 : data = g_new0 (struct SetTest, 1);
1135 : 1 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1136 : :
1137 : : /* g_object_get() will take a reference. Increasing the ref count from 1 to 2
1138 : : * is more expensive, due to the check for toggle notifications. We have a
1139 : : * performance test for that already. Don't also test that overhead during
1140 : : * "property-get" test and avoid this by taking an additional reference. */
1141 : 1 : g_object_ref (data->object);
1142 : :
1143 : 1 : return data;
1144 : : }
1145 : :
1146 : : static void
1147 : 7 : test_set_init (PerformanceTest *test,
1148 : : void *_data,
1149 : : double factor)
1150 : : {
1151 : 7 : struct SetTest *data = _data;
1152 : :
1153 : 7 : data->n_checks = (unsigned int) (factor * NUM_SET_PER_ROUND);
1154 : 7 : }
1155 : :
1156 : : static void
1157 : 7 : test_set_finish (PerformanceTest *test,
1158 : : void *data)
1159 : : {
1160 : 7 : }
1161 : :
1162 : : static void
1163 : 1 : test_set_print_result (PerformanceTest *test,
1164 : : void *_data,
1165 : : double time)
1166 : : {
1167 : 1 : struct SetTest *data = _data;
1168 : :
1169 : 1 : g_print ("Property set per second: %.0f\n",
1170 : 1 : data->n_checks / time);
1171 : 1 : }
1172 : :
1173 : : static void
1174 : 1 : test_set_teardown (PerformanceTest *test,
1175 : : void *_data)
1176 : : {
1177 : 1 : struct SetTest *data = _data;
1178 : :
1179 : 1 : g_object_unref (data->object);
1180 : 1 : g_object_unref (data->object);
1181 : 1 : g_free (data);
1182 : 1 : }
1183 : :
1184 : : /*************************************************************
1185 : : * Test object get performance
1186 : : *************************************************************/
1187 : :
1188 : : #define NUM_GET_PER_ROUND 10000
1189 : :
1190 : : struct GetTest {
1191 : : GObject *object;
1192 : : unsigned int n_checks;
1193 : : };
1194 : :
1195 : : static void
1196 : 7 : test_get_run (PerformanceTest *test,
1197 : : void *_data)
1198 : : {
1199 : 7 : struct GetTest *data = _data;
1200 : 7 : GObject *object = data->object;
1201 : : int val;
1202 : :
1203 : 63211 : for (unsigned int i = 0; i < data->n_checks; i++)
1204 : 63204 : g_object_get (object, "val1", &val, NULL);
1205 : 7 : }
1206 : :
1207 : : static void *
1208 : 1 : test_get_setup (PerformanceTest *test)
1209 : : {
1210 : : struct GetTest *data;
1211 : :
1212 : 1 : data = g_new0 (struct GetTest, 1);
1213 : 1 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1214 : :
1215 : : /* g_object_get() will take a reference. Increasing the ref count from 1 to 2
1216 : : * is more expensive, due to the check for toggle notifications. We have a
1217 : : * performance test for that already. Don't also test that overhead during
1218 : : * "property-get" test and avoid this by taking an additional reference. */
1219 : 1 : g_object_ref (data->object);
1220 : :
1221 : 1 : return data;
1222 : : }
1223 : :
1224 : : static void
1225 : 7 : test_get_init (PerformanceTest *test,
1226 : : void *_data,
1227 : : double factor)
1228 : : {
1229 : 7 : struct GetTest *data = _data;
1230 : :
1231 : 7 : data->n_checks = (unsigned int) (factor * NUM_GET_PER_ROUND);
1232 : 7 : }
1233 : :
1234 : : static void
1235 : 7 : test_get_finish (PerformanceTest *test,
1236 : : void *data)
1237 : : {
1238 : 7 : }
1239 : :
1240 : : static void
1241 : 1 : test_get_print_result (PerformanceTest *test,
1242 : : void *_data,
1243 : : double time)
1244 : : {
1245 : 1 : struct GetTest *data = _data;
1246 : :
1247 : 1 : g_print ("Property get per second: %.0f\n",
1248 : 1 : data->n_checks / time);
1249 : 1 : }
1250 : :
1251 : : static void
1252 : 1 : test_get_teardown (PerformanceTest *test,
1253 : : gpointer _data)
1254 : : {
1255 : 1 : struct GetTest *data = _data;
1256 : :
1257 : 1 : g_object_unref (data->object);
1258 : 1 : g_object_unref (data->object);
1259 : 1 : g_free (data);
1260 : 1 : }
1261 : :
1262 : : /*************************************************************
1263 : : * Test object refcount performance
1264 : : *************************************************************/
1265 : :
1266 : : #define NUM_KILO_REFS_PER_ROUND 100000
1267 : :
1268 : : struct RefcountTest {
1269 : : GObject *object;
1270 : : unsigned int n_checks;
1271 : : gboolean is_toggle_ref;
1272 : : };
1273 : :
1274 : : static void
1275 : 1221045 : test_refcount_toggle_ref_cb (gpointer data,
1276 : : GObject *object,
1277 : : gboolean is_last_ref)
1278 : : {
1279 : 1221045 : }
1280 : :
1281 : : static gpointer
1282 : 3 : test_refcount_setup (PerformanceTest *test)
1283 : : {
1284 : : struct RefcountTest *data;
1285 : :
1286 : 3 : data = g_new0 (struct RefcountTest, 1);
1287 : 3 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1288 : :
1289 : 3 : if (g_str_equal (test->name, "refcount-toggle"))
1290 : : {
1291 : 1 : g_object_add_toggle_ref (data->object, test_refcount_toggle_ref_cb, NULL);
1292 : 1 : g_object_unref (data->object);
1293 : 1 : data->is_toggle_ref = TRUE;
1294 : : }
1295 : :
1296 : 3 : return data;
1297 : : }
1298 : :
1299 : : static void
1300 : 21 : test_refcount_init (PerformanceTest *test,
1301 : : gpointer _data,
1302 : : double factor)
1303 : : {
1304 : 21 : struct RefcountTest *data = _data;
1305 : :
1306 : 21 : data->n_checks = (unsigned int) (factor * NUM_KILO_REFS_PER_ROUND);
1307 : 21 : }
1308 : :
1309 : : static void
1310 : 7 : test_refcount_run (PerformanceTest *test,
1311 : : gpointer _data)
1312 : : {
1313 : 7 : struct RefcountTest *data = _data;
1314 : 7 : GObject *object = data->object;
1315 : :
1316 : 604912 : for (unsigned int i = 0; i < data->n_checks; i++)
1317 : : {
1318 : 604905 : g_object_ref (object);
1319 : 604905 : g_object_ref (object);
1320 : 604905 : g_object_ref (object);
1321 : 604905 : g_object_unref (object);
1322 : 604905 : g_object_unref (object);
1323 : :
1324 : 604905 : g_object_ref (object);
1325 : 604905 : g_object_ref (object);
1326 : 604905 : g_object_unref (object);
1327 : 604905 : g_object_unref (object);
1328 : 604905 : g_object_unref (object);
1329 : : }
1330 : 7 : }
1331 : :
1332 : : static void
1333 : 14 : test_refcount_1_run (PerformanceTest *test,
1334 : : gpointer _data)
1335 : : {
1336 : 14 : struct RefcountTest *data = _data;
1337 : 14 : GObject *object = data->object;
1338 : :
1339 : 1229286 : for (unsigned int i = 0; i < data->n_checks; i++)
1340 : : {
1341 : 1229272 : g_object_ref (object);
1342 : 1229272 : g_object_unref (object);
1343 : : }
1344 : 14 : }
1345 : :
1346 : : static void
1347 : 21 : test_refcount_finish (PerformanceTest *test,
1348 : : gpointer _data)
1349 : : {
1350 : 21 : }
1351 : :
1352 : : static void
1353 : 3 : test_refcount_print_result (PerformanceTest *test,
1354 : : gpointer _data,
1355 : : double time)
1356 : : {
1357 : 3 : struct RefcountTest *data = _data;
1358 : 3 : g_print ("Million refs+unref per second: %.2f\n",
1359 : 3 : data->n_checks * 5 / (time * 1000000 ));
1360 : 3 : }
1361 : :
1362 : : static void
1363 : 3 : test_refcount_teardown (PerformanceTest *test,
1364 : : gpointer _data)
1365 : : {
1366 : 3 : struct RefcountTest *data = _data;
1367 : :
1368 : 3 : if (data->is_toggle_ref)
1369 : 1 : g_object_remove_toggle_ref (data->object, test_refcount_toggle_ref_cb, NULL);
1370 : : else
1371 : 2 : g_object_unref (data->object);
1372 : :
1373 : 3 : g_free (data);
1374 : 3 : }
1375 : :
1376 : : /*************************************************************
1377 : : * Main test code
1378 : : *************************************************************/
1379 : :
1380 : : static PerformanceTest tests[] = {
1381 : : {
1382 : : "simple-construction",
1383 : : simple_object_get_type,
1384 : : test_construction_setup,
1385 : : test_construction_init,
1386 : : test_construction_run,
1387 : : test_construction_finish,
1388 : : test_construction_teardown,
1389 : : test_construction_print_result
1390 : : },
1391 : : {
1392 : : "simple-construction1",
1393 : : simple_object_get_type,
1394 : : test_construction_setup,
1395 : : test_construction_init,
1396 : : test_construction_run1,
1397 : : test_construction_finish1,
1398 : : test_construction_teardown,
1399 : : test_construction_print_result
1400 : : },
1401 : : {
1402 : : "complex-construction",
1403 : : complex_object_get_type,
1404 : : test_construction_setup,
1405 : : test_construction_init,
1406 : : test_complex_construction_run,
1407 : : test_construction_finish,
1408 : : test_construction_teardown,
1409 : : test_construction_print_result
1410 : : },
1411 : : {
1412 : : "complex-construction1",
1413 : : complex_object_get_type,
1414 : : test_construction_setup,
1415 : : test_construction_init,
1416 : : test_complex_construction_run1,
1417 : : test_construction_finish,
1418 : : test_construction_teardown,
1419 : : test_construction_print_result
1420 : : },
1421 : : {
1422 : : "complex-construction2",
1423 : : complex_object_get_type,
1424 : : test_construction_setup,
1425 : : test_construction_init,
1426 : : test_complex_construction_run2,
1427 : : test_construction_finish,
1428 : : test_construction_teardown,
1429 : : test_construction_print_result
1430 : : },
1431 : : {
1432 : : "finalization",
1433 : : simple_object_get_type,
1434 : : test_construction_setup,
1435 : : test_finalization_init,
1436 : : test_finalization_run,
1437 : : test_finalization_finish,
1438 : : test_construction_teardown,
1439 : : test_finalization_print_result
1440 : : },
1441 : : {
1442 : : "type-check",
1443 : : NULL,
1444 : : test_type_check_setup,
1445 : : test_type_check_init,
1446 : : test_type_check_run,
1447 : : test_type_check_finish,
1448 : : test_type_check_teardown,
1449 : : test_type_check_print_result
1450 : : },
1451 : : {
1452 : : "emit-unhandled",
1453 : : GUINT_TO_POINTER (COMPLEX_SIGNAL),
1454 : : test_emission_unhandled_setup,
1455 : : test_emission_unhandled_init,
1456 : : test_emission_run,
1457 : : test_emission_unhandled_finish,
1458 : : test_emission_unhandled_teardown,
1459 : : test_emission_unhandled_print_result
1460 : : },
1461 : : {
1462 : : "emit-unhandled-empty",
1463 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
1464 : : test_emission_unhandled_setup,
1465 : : test_emission_unhandled_init,
1466 : : test_emission_run,
1467 : : test_emission_unhandled_finish,
1468 : : test_emission_unhandled_teardown,
1469 : : test_emission_unhandled_print_result
1470 : : },
1471 : : {
1472 : : "emit-unhandled-generic",
1473 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
1474 : : test_emission_unhandled_setup,
1475 : : test_emission_unhandled_init,
1476 : : test_emission_run,
1477 : : test_emission_unhandled_finish,
1478 : : test_emission_unhandled_teardown,
1479 : : test_emission_unhandled_print_result
1480 : : },
1481 : : {
1482 : : "emit-unhandled-generic-empty",
1483 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
1484 : : test_emission_unhandled_setup,
1485 : : test_emission_unhandled_init,
1486 : : test_emission_run,
1487 : : test_emission_unhandled_finish,
1488 : : test_emission_unhandled_teardown,
1489 : : test_emission_unhandled_print_result
1490 : : },
1491 : : {
1492 : : "emit-unhandled-args",
1493 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
1494 : : test_emission_unhandled_setup,
1495 : : test_emission_unhandled_init,
1496 : : test_emission_run_args,
1497 : : test_emission_unhandled_finish,
1498 : : test_emission_unhandled_teardown,
1499 : : test_emission_unhandled_print_result
1500 : : },
1501 : : {
1502 : : "emit-handled",
1503 : : GUINT_TO_POINTER (COMPLEX_SIGNAL),
1504 : : test_emission_handled_setup,
1505 : : test_emission_handled_init,
1506 : : test_emission_run,
1507 : : test_emission_handled_finish,
1508 : : test_emission_handled_teardown,
1509 : : test_emission_handled_print_result
1510 : : },
1511 : : {
1512 : : "emit-handled-empty",
1513 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
1514 : : test_emission_handled_setup,
1515 : : test_emission_handled_init,
1516 : : test_emission_run,
1517 : : test_emission_handled_finish,
1518 : : test_emission_handled_teardown,
1519 : : test_emission_handled_print_result
1520 : : },
1521 : : {
1522 : : "emit-handled-generic",
1523 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
1524 : : test_emission_handled_setup,
1525 : : test_emission_handled_init,
1526 : : test_emission_run,
1527 : : test_emission_handled_finish,
1528 : : test_emission_handled_teardown,
1529 : : test_emission_handled_print_result
1530 : : },
1531 : : {
1532 : : "emit-handled-generic-empty",
1533 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
1534 : : test_emission_handled_setup,
1535 : : test_emission_handled_init,
1536 : : test_emission_run,
1537 : : test_emission_handled_finish,
1538 : : test_emission_handled_teardown,
1539 : : test_emission_handled_print_result
1540 : : },
1541 : : {
1542 : : "emit-handled-args",
1543 : : GUINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
1544 : : test_emission_handled_setup,
1545 : : test_emission_handled_init,
1546 : : test_emission_run_args,
1547 : : test_emission_handled_finish,
1548 : : test_emission_handled_teardown,
1549 : : test_emission_handled_print_result
1550 : : },
1551 : : {
1552 : : "notify-unhandled",
1553 : : complex_object_get_type,
1554 : : test_notify_unhandled_setup,
1555 : : test_notify_unhandled_init,
1556 : : test_notify_run,
1557 : : test_notify_unhandled_finish,
1558 : : test_notify_unhandled_teardown,
1559 : : test_notify_unhandled_print_result
1560 : : },
1561 : : {
1562 : : "notify-by-pspec-unhandled",
1563 : : complex_object_get_type,
1564 : : test_notify_unhandled_setup,
1565 : : test_notify_unhandled_init,
1566 : : test_notify_by_pspec_run,
1567 : : test_notify_unhandled_finish,
1568 : : test_notify_unhandled_teardown,
1569 : : test_notify_unhandled_print_result
1570 : : },
1571 : : {
1572 : : "notify-handled",
1573 : : complex_object_get_type,
1574 : : test_notify_handled_setup,
1575 : : test_notify_handled_init,
1576 : : test_notify_run,
1577 : : test_notify_handled_finish,
1578 : : test_notify_handled_teardown,
1579 : : test_notify_handled_print_result
1580 : : },
1581 : : {
1582 : : "notify-by-pspec-handled",
1583 : : complex_object_get_type,
1584 : : test_notify_handled_setup,
1585 : : test_notify_handled_init,
1586 : : test_notify_by_pspec_run,
1587 : : test_notify_handled_finish,
1588 : : test_notify_handled_teardown,
1589 : : test_notify_handled_print_result
1590 : : },
1591 : : {
1592 : : "property-set",
1593 : : complex_object_get_type,
1594 : : test_set_setup,
1595 : : test_set_init,
1596 : : test_set_run,
1597 : : test_set_finish,
1598 : : test_set_teardown,
1599 : : test_set_print_result
1600 : : },
1601 : : {
1602 : : "property-get",
1603 : : complex_object_get_type,
1604 : : test_get_setup,
1605 : : test_get_init,
1606 : : test_get_run,
1607 : : test_get_finish,
1608 : : test_get_teardown,
1609 : : test_get_print_result
1610 : : },
1611 : : {
1612 : : "refcount",
1613 : : NULL,
1614 : : test_refcount_setup,
1615 : : test_refcount_init,
1616 : : test_refcount_run,
1617 : : test_refcount_finish,
1618 : : test_refcount_teardown,
1619 : : test_refcount_print_result
1620 : : },
1621 : : {
1622 : : "refcount-1",
1623 : : NULL,
1624 : : test_refcount_setup,
1625 : : test_refcount_init,
1626 : : test_refcount_1_run,
1627 : : test_refcount_finish,
1628 : : test_refcount_teardown,
1629 : : test_refcount_print_result
1630 : : },
1631 : : {
1632 : : "refcount-toggle",
1633 : : NULL,
1634 : : test_refcount_setup,
1635 : : test_refcount_init,
1636 : : test_refcount_1_run,
1637 : : test_refcount_finish,
1638 : : test_refcount_teardown,
1639 : : test_refcount_print_result
1640 : : },
1641 : : };
1642 : :
1643 : : static PerformanceTest *
1644 : 0 : find_test (const char *name)
1645 : : {
1646 : 0 : for (size_t i = 0; i < G_N_ELEMENTS (tests); i++)
1647 : : {
1648 : 0 : if (strcmp (tests[i].name, name) == 0)
1649 : 0 : return &tests[i];
1650 : : }
1651 : 0 : return NULL;
1652 : : }
1653 : : int
1654 : 1 : main (int argc,
1655 : : char *argv[])
1656 : : {
1657 : : PerformanceTest *test;
1658 : : GOptionContext *context;
1659 : 1 : GError *error = NULL;
1660 : : const char *str;
1661 : :
1662 : 1 : if ((str = g_getenv ("GLIB_PERFORMANCE_FACTOR")) && str[0])
1663 : : {
1664 : 0 : test_factor = g_strtod (str, NULL);
1665 : : }
1666 : :
1667 : 1 : context = g_option_context_new ("GObject performance tests");
1668 : 1 : g_option_context_add_main_entries (context, cmd_entries, NULL);
1669 : 1 : if (!g_option_context_parse (context, &argc, &argv, &error))
1670 : : {
1671 : 0 : g_printerr ("%s: %s\n", argv[0], error->message);
1672 : 0 : return 1;
1673 : : }
1674 : :
1675 : 1 : if (test_factor < 0)
1676 : : {
1677 : 0 : g_printerr ("%s: test factor must be positive\n", argv[0]);
1678 : 0 : return 1;
1679 : : }
1680 : :
1681 : 1 : global_timer = g_timer_new ();
1682 : :
1683 : 1 : if (argc > 1)
1684 : : {
1685 : 0 : for (int i = 1; i < argc; i++)
1686 : : {
1687 : 0 : test = find_test (argv[i]);
1688 : 0 : if (test)
1689 : 0 : run_test (test);
1690 : : }
1691 : : }
1692 : : else
1693 : : {
1694 : 27 : for (size_t k = 0; k < G_N_ELEMENTS (tests); k++)
1695 : 26 : run_test (&tests[k]);
1696 : : }
1697 : :
1698 : 1 : g_option_context_free (context);
1699 : 1 : g_clear_pointer (&global_timer, g_timer_destroy);
1700 : 1 : return 0;
1701 : : }
|