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 : 92 : for (i = 0; TRUE; i++)
94 : : {
95 : 92 : test->init (test, data, 1.0);
96 : 92 : test->run (test, data);
97 : 92 : test->finish (test, data);
98 : :
99 [ + - ]: 92 : 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 [ + + ]: 92 : else if (global_timer)
107 : : {
108 [ + + ]: 67 : 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 : 66 : 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 = (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 : 844431 : simple_object_finalize (GObject *object)
246 : : {
247 : 844431 : G_OBJECT_CLASS (simple_object_parent_class)->finalize (object);
248 : 844431 : }
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 : 844431 : simple_object_init (SimpleObject *simple_object)
260 : : {
261 : 844431 : simple_object->val = 42;
262 : 844431 : }
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 [ + + + - : 789798 : 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 : 254048 : complex_object_finalize (GObject *object)
356 : : {
357 : 254048 : ComplexObject *c = COMPLEX_OBJECT (object);
358 : :
359 : 254048 : g_free (c->val2);
360 : :
361 : 254048 : G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
362 : 254048 : }
363 : :
364 : : static void
365 : 429456 : complex_object_set_property (GObject *object,
366 : : guint prop_id,
367 : : const GValue *value,
368 : : GParamSpec *pspec)
369 : : {
370 : 429456 : ComplexObject *complex = COMPLEX_OBJECT (object);
371 : :
372 [ + + - ]: 429456 : switch (prop_id)
373 : : {
374 : 356966 : case PROP_VAL1:
375 : 356966 : complex->val1 = g_value_get_int (value);
376 : 356966 : break;
377 : 72490 : case PROP_VAL2:
378 : 72490 : g_free (complex->val2);
379 : 72490 : complex->val2 = g_value_dup_string (value);
380 : 72490 : break;
381 : 0 : default:
382 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
383 : 0 : break;
384 : : }
385 : 429456 : }
386 : :
387 : : static void
388 : 106269 : complex_object_get_property (GObject *object,
389 : : guint prop_id,
390 : : GValue *value,
391 : : GParamSpec *pspec)
392 : : {
393 : 106269 : ComplexObject *complex = COMPLEX_OBJECT (object);
394 : :
395 [ + - - ]: 106269 : switch (prop_id)
396 : : {
397 : 106269 : case PROP_VAL1:
398 : 106269 : g_value_set_int (value, complex->val1);
399 : 106269 : 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 : 106269 : }
408 : :
409 : : static void
410 : 425846 : complex_object_real_signal (ComplexObject *obj)
411 : : {
412 : 425846 : }
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 : 254048 : complex_object_init (ComplexObject *complex_object)
496 : : {
497 : 254048 : complex_object->val1 = 42;
498 : 254048 : }
499 : :
500 : : /*************************************************************
501 : : * Test object construction performance
502 : : *************************************************************/
503 : :
504 : : #define NUM_OBJECT_TO_CONSTRUCT 10000
505 : :
506 : : struct ConstructionTest {
507 : : GObject **objects;
508 : : 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 : 101 : test_construction_init (PerformanceTest *test,
525 : : gpointer _data,
526 : : double count_factor)
527 : : {
528 : 101 : struct ConstructionTest *data = _data;
529 : : int n;
530 : :
531 : 101 : n = NUM_OBJECT_TO_CONSTRUCT * count_factor;
532 [ + + ]: 101 : if (data->n_objects != n)
533 : : {
534 : 10 : data->n_objects = n;
535 : 10 : data->objects = g_renew (GObject *, data->objects, n);
536 : : }
537 : 101 : }
538 : :
539 : : static void
540 : 73 : test_construction_run (PerformanceTest *test,
541 : : gpointer _data)
542 : : {
543 : 73 : struct ConstructionTest *data = _data;
544 : 73 : GObject **objects = data->objects;
545 : 73 : GType type = data->type;
546 : : int i, n_objects;
547 : :
548 : 73 : n_objects = data->n_objects;
549 [ + + ]: 780313 : for (i = 0; i < n_objects; i++)
550 : 780240 : objects[i] = g_object_new (type, NULL);
551 : 73 : }
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 : : int i, n_objects;
560 : :
561 : 7 : n_objects = data->n_objects;
562 [ + + ]: 143080 : for (i = 0; i < n_objects; i++)
563 : 143073 : 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 : : int i, n_objects;
574 : :
575 : 7 : n_objects = data->n_objects;
576 [ + + ]: 72497 : for (i = 0; i < n_objects; i++)
577 : 72490 : 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 : : int i, n_objects;
588 : :
589 : 7 : n_objects = data->n_objects;
590 [ + + ]: 84110 : for (i = 0; i < n_objects; i++)
591 : : {
592 : : ComplexObject *object;
593 : 84103 : object = (ComplexObject *)g_object_new (type, NULL);
594 : 84103 : object->val1 = 5;
595 : 84103 : object->val2 = g_strdup ("thousand");
596 : 84103 : 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 : : int i, n_objects;
608 : :
609 : 7 : n_objects = data->n_objects;
610 [ + + ]: 97442 : for (i = 0; i < n_objects; i++)
611 : : {
612 : 97435 : objects[i] = g_object_new (type, NULL);
613 : : }
614 : 7 : }
615 : :
616 : : static void
617 : 94 : test_construction_finish (PerformanceTest *test,
618 : : gpointer _data)
619 : : {
620 : 94 : struct ConstructionTest *data = _data;
621 : : int i;
622 : :
623 [ + + ]: 1034362 : for (i = 0; i < data->n_objects; i++)
624 : 1034268 : g_object_unref (data->objects[i]);
625 : 94 : }
626 : :
627 : : static void
628 : 7 : test_construction_finish1 (PerformanceTest *test,
629 : : gpointer _data)
630 : : {
631 : 7 : struct ConstructionTest *data = _data;
632 : : int i;
633 : :
634 [ + + ]: 143080 : for (i = 0; i < data->n_objects; i++)
635 : 143073 : g_slice_free (SimpleObject, (SimpleObject *)data->objects[i]);
636 : 7 : }
637 : :
638 : : static void
639 : 6 : test_construction_teardown (PerformanceTest *test,
640 : : gpointer _data)
641 : : {
642 : 6 : struct ConstructionTest *data = _data;
643 : 6 : g_free (data->objects);
644 : 6 : g_free (data);
645 : 6 : }
646 : :
647 : : static void
648 : 7 : test_finalization_init (PerformanceTest *test,
649 : : gpointer _data,
650 : : double count_factor)
651 : : {
652 : 7 : struct ConstructionTest *data = _data;
653 : : int n;
654 : :
655 : 7 : n = NUM_OBJECT_TO_CONSTRUCT * count_factor;
656 [ + + ]: 7 : if (data->n_objects != n)
657 : : {
658 : 2 : data->n_objects = n;
659 : 2 : data->objects = g_renew (GObject *, data->objects, n);
660 : : }
661 : :
662 [ + + ]: 64198 : for (int i = 0; i < data->n_objects; i++)
663 : : {
664 : 64191 : data->objects[i] = g_object_new (data->type, NULL);
665 : : }
666 : 7 : }
667 : :
668 : : static void
669 : 7 : test_finalization_run (PerformanceTest *test,
670 : : gpointer _data)
671 : : {
672 : 7 : struct ConstructionTest *data = _data;
673 : 7 : GObject **objects = data->objects;
674 : : int i, n_objects;
675 : :
676 : 7 : n_objects = data->n_objects;
677 [ + + ]: 64198 : for (i = 0; i < n_objects; i++)
678 : : {
679 : 64191 : g_object_unref (objects[i]);
680 : : }
681 : 7 : }
682 : :
683 : : static void
684 : 7 : test_finalization_finish (PerformanceTest *test,
685 : : gpointer _data)
686 : : {
687 : 7 : }
688 : :
689 : : static void
690 : 5 : test_construction_print_result (PerformanceTest *test,
691 : : gpointer _data,
692 : : double time)
693 : : {
694 : 5 : struct ConstructionTest *data = _data;
695 : :
696 : 5 : g_print ("Millions of constructed objects per second: %.3f\n",
697 : 5 : data->n_objects / (time * 1000000));
698 : 5 : }
699 : :
700 : : static void
701 : 1 : test_finalization_print_result (PerformanceTest *test,
702 : : gpointer _data,
703 : : double time)
704 : : {
705 : 1 : struct ConstructionTest *data = _data;
706 : :
707 : 1 : g_print ("Millions of finalized objects per second: %.3f\n",
708 : 1 : data->n_objects / (time * 1000000));
709 : 1 : }
710 : :
711 : : /*************************************************************
712 : : * Test runtime type check performance
713 : : *************************************************************/
714 : :
715 : : #define NUM_KILO_CHECKS_PER_ROUND 50
716 : :
717 : : struct TypeCheckTest {
718 : : GObject *object;
719 : : int n_checks;
720 : : };
721 : :
722 : : static gpointer
723 : 1 : test_type_check_setup (PerformanceTest *test)
724 : : {
725 : : struct TypeCheckTest *data;
726 : :
727 : 1 : data = g_new0 (struct TypeCheckTest, 1);
728 : 1 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
729 : :
730 : 1 : return data;
731 : : }
732 : :
733 : : static void
734 : 7 : test_type_check_init (PerformanceTest *test,
735 : : gpointer _data,
736 : : double factor)
737 : : {
738 : 7 : struct TypeCheckTest *data = _data;
739 : :
740 : 7 : data->n_checks = factor * NUM_KILO_CHECKS_PER_ROUND;
741 : 7 : }
742 : :
743 : :
744 : : /* Work around g_type_check_instance_is_a being marked "pure",
745 : : and thus only called once for the loop. */
746 : : gboolean (*my_type_check_instance_is_a) (GTypeInstance *type_instance,
747 : : GType iface_type) = &g_type_check_instance_is_a;
748 : :
749 : : static void
750 : 7 : test_type_check_run (PerformanceTest *test,
751 : : gpointer _data)
752 : : {
753 : 7 : struct TypeCheckTest *data = _data;
754 : 7 : GObject *object = data->object;
755 : : GType type, types[5];
756 : : int i, j;
757 : :
758 : 7 : types[0] = test_iface1_get_type ();
759 : 7 : types[1] = test_iface2_get_type ();
760 : 7 : types[2] = test_iface3_get_type ();
761 : 7 : types[3] = test_iface4_get_type ();
762 : 7 : types[4] = test_iface5_get_type ();
763 : :
764 [ + + ]: 478 : for (i = 0; i < data->n_checks; i++)
765 : : {
766 : 471 : type = types[i%5];
767 [ + + ]: 471471 : for (j = 0; j < 1000; j++)
768 : : {
769 : 471000 : my_type_check_instance_is_a ((GTypeInstance *)object,
770 : : type);
771 : : }
772 : : }
773 : 7 : }
774 : :
775 : : static void
776 : 7 : test_type_check_finish (PerformanceTest *test,
777 : : gpointer data)
778 : : {
779 : 7 : }
780 : :
781 : : static void
782 : 1 : test_type_check_print_result (PerformanceTest *test,
783 : : gpointer _data,
784 : : double time)
785 : : {
786 : 1 : struct TypeCheckTest *data = _data;
787 : 1 : g_print ("Million type checks per second: %.2f\n",
788 : 1 : data->n_checks / (1000*time));
789 : 1 : }
790 : :
791 : : static void
792 : 1 : test_type_check_teardown (PerformanceTest *test,
793 : : gpointer _data)
794 : : {
795 : 1 : struct TypeCheckTest *data = _data;
796 : :
797 : 1 : g_object_unref (data->object);
798 : 1 : g_free (data);
799 : 1 : }
800 : :
801 : : /*************************************************************
802 : : * Test signal emissions performance (common code)
803 : : *************************************************************/
804 : :
805 : : #define NUM_EMISSIONS_PER_ROUND 10000
806 : :
807 : : struct EmissionTest {
808 : : GObject *object;
809 : : int n_checks;
810 : : int signal_id;
811 : : };
812 : :
813 : : static void
814 : 56 : test_emission_run (PerformanceTest *test,
815 : : gpointer _data)
816 : : {
817 : 56 : struct EmissionTest *data = _data;
818 : 56 : GObject *object = data->object;
819 : : int i;
820 : :
821 [ + + ]: 755398 : for (i = 0; i < data->n_checks; i++)
822 : 755342 : g_signal_emit (object, data->signal_id, 0);
823 : 56 : }
824 : :
825 : : static void
826 : 14 : test_emission_run_args (PerformanceTest *test,
827 : : gpointer _data)
828 : : {
829 : 14 : struct EmissionTest *data = _data;
830 : 14 : GObject *object = data->object;
831 : : int i;
832 : :
833 [ + + ]: 138081 : for (i = 0; i < data->n_checks; i++)
834 : 138067 : g_signal_emit (object, data->signal_id, 0, 0, NULL);
835 : 14 : }
836 : :
837 : : /*************************************************************
838 : : * Test signal unhandled emissions performance
839 : : *************************************************************/
840 : :
841 : : static gpointer
842 : 5 : test_emission_unhandled_setup (PerformanceTest *test)
843 : : {
844 : : struct EmissionTest *data;
845 : :
846 : 5 : data = g_new0 (struct EmissionTest, 1);
847 : 5 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
848 : 5 : data->signal_id = complex_signals[GPOINTER_TO_INT (test->extra_data)];
849 : 5 : return data;
850 : : }
851 : :
852 : : static void
853 : 35 : test_emission_unhandled_init (PerformanceTest *test,
854 : : gpointer _data,
855 : : double factor)
856 : : {
857 : 35 : struct EmissionTest *data = _data;
858 : :
859 : 35 : data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
860 : 35 : }
861 : :
862 : : static void
863 : 35 : test_emission_unhandled_finish (PerformanceTest *test,
864 : : gpointer data)
865 : : {
866 : 35 : }
867 : :
868 : : static void
869 : 5 : test_emission_unhandled_print_result (PerformanceTest *test,
870 : : gpointer _data,
871 : : double time)
872 : : {
873 : 5 : struct EmissionTest *data = _data;
874 : :
875 : 5 : g_print ("Emissions per second: %.0f\n",
876 : 5 : data->n_checks / time);
877 : 5 : }
878 : :
879 : : static void
880 : 5 : test_emission_unhandled_teardown (PerformanceTest *test,
881 : : gpointer _data)
882 : : {
883 : 5 : struct EmissionTest *data = _data;
884 : :
885 : 5 : g_object_unref (data->object);
886 : 5 : g_free (data);
887 : 5 : }
888 : :
889 : : /*************************************************************
890 : : * Test signal handled emissions performance
891 : : *************************************************************/
892 : :
893 : : static void
894 : 348873 : test_emission_handled_handler (ComplexObject *obj, gpointer data)
895 : : {
896 : 348873 : }
897 : :
898 : : static gpointer
899 : 5 : test_emission_handled_setup (PerformanceTest *test)
900 : : {
901 : : struct EmissionTest *data;
902 : :
903 : 5 : data = g_new0 (struct EmissionTest, 1);
904 : 5 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
905 : 5 : data->signal_id = complex_signals[GPOINTER_TO_INT (test->extra_data)];
906 : 5 : g_signal_connect (data->object, "signal",
907 : : G_CALLBACK (test_emission_handled_handler),
908 : : NULL);
909 : 5 : g_signal_connect (data->object, "signal-empty",
910 : : G_CALLBACK (test_emission_handled_handler),
911 : : NULL);
912 : 5 : g_signal_connect (data->object, "signal-generic",
913 : : G_CALLBACK (test_emission_handled_handler),
914 : : NULL);
915 : 5 : g_signal_connect (data->object, "signal-generic-empty",
916 : : G_CALLBACK (test_emission_handled_handler),
917 : : NULL);
918 : 5 : g_signal_connect (data->object, "signal-args",
919 : : G_CALLBACK (test_emission_handled_handler),
920 : : NULL);
921 : :
922 : 5 : return data;
923 : : }
924 : :
925 : : static void
926 : 35 : test_emission_handled_init (PerformanceTest *test,
927 : : gpointer _data,
928 : : double factor)
929 : : {
930 : 35 : struct EmissionTest *data = _data;
931 : :
932 : 35 : data->n_checks = factor * NUM_EMISSIONS_PER_ROUND;
933 : 35 : }
934 : :
935 : : static void
936 : 35 : test_emission_handled_finish (PerformanceTest *test,
937 : : gpointer data)
938 : : {
939 : 35 : }
940 : :
941 : : static void
942 : 5 : test_emission_handled_print_result (PerformanceTest *test,
943 : : gpointer _data,
944 : : double time)
945 : : {
946 : 5 : struct EmissionTest *data = _data;
947 : :
948 : 5 : g_print ("Emissions per second: %.0f\n",
949 : 5 : data->n_checks / time);
950 : 5 : }
951 : :
952 : : static void
953 : 5 : test_emission_handled_teardown (PerformanceTest *test,
954 : : gpointer _data)
955 : : {
956 : 5 : struct EmissionTest *data = _data;
957 : :
958 : 5 : g_object_unref (data->object);
959 : 5 : g_free (data);
960 : 5 : }
961 : :
962 : : /*************************************************************
963 : : * Test object notify performance (common code)
964 : : *************************************************************/
965 : :
966 : : #define NUM_NOTIFY_PER_ROUND 10000
967 : :
968 : : struct NotifyTest {
969 : : GObject *object;
970 : : unsigned n_checks;
971 : : };
972 : :
973 : : static void
974 : 14 : test_notify_run (PerformanceTest *test,
975 : : void *_data)
976 : : {
977 : 14 : struct NotifyTest *data = _data;
978 : 14 : GObject *object = data->object;
979 : :
980 [ + + ]: 174155 : for (unsigned i = 0; i < data->n_checks; i++)
981 : 174141 : g_object_notify (object, "val1");
982 : 14 : }
983 : :
984 : : static void
985 : 14 : test_notify_by_pspec_run (PerformanceTest *test,
986 : : void *_data)
987 : : {
988 : 14 : struct NotifyTest *data = _data;
989 : 14 : GObject *object = data->object;
990 : :
991 [ + + ]: 412347 : for (unsigned i = 0; i < data->n_checks; i++)
992 : 412333 : g_object_notify_by_pspec (object, pspecs[PROP_VAL1]);
993 : 14 : }
994 : :
995 : : /*************************************************************
996 : : * Test notify unhandled performance
997 : : *************************************************************/
998 : :
999 : : static void *
1000 : 2 : test_notify_unhandled_setup (PerformanceTest *test)
1001 : : {
1002 : : struct NotifyTest *data;
1003 : :
1004 : 2 : data = g_new0 (struct NotifyTest, 1);
1005 : 2 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1006 : 2 : return data;
1007 : : }
1008 : :
1009 : : static void
1010 : 14 : test_notify_unhandled_init (PerformanceTest *test,
1011 : : void *_data,
1012 : : double factor)
1013 : : {
1014 : 14 : struct NotifyTest *data = _data;
1015 : :
1016 : 14 : data->n_checks = factor * NUM_NOTIFY_PER_ROUND;
1017 : 14 : }
1018 : :
1019 : : static void
1020 : 14 : test_notify_unhandled_finish (PerformanceTest *test,
1021 : : void *data)
1022 : : {
1023 : 14 : }
1024 : :
1025 : : static void
1026 : 2 : test_notify_unhandled_print_result (PerformanceTest *test,
1027 : : void *_data,
1028 : : double time)
1029 : : {
1030 : 2 : struct NotifyTest *data = _data;
1031 : :
1032 : 2 : g_print ("Notify (unhandled) per second: %.0f\n",
1033 : 2 : data->n_checks / time);
1034 : 2 : }
1035 : :
1036 : : static void
1037 : 2 : test_notify_unhandled_teardown (PerformanceTest *test,
1038 : : void *_data)
1039 : : {
1040 : 2 : struct NotifyTest *data = _data;
1041 : :
1042 : 2 : g_object_unref (data->object);
1043 : 2 : g_free (data);
1044 : 2 : }
1045 : :
1046 : : /*************************************************************
1047 : : * Test notify handled performance
1048 : : *************************************************************/
1049 : :
1050 : : static void
1051 : 130717 : test_notify_handled_handler (ComplexObject *obj, GParamSpec *pspec, void *data)
1052 : : {
1053 : 130717 : }
1054 : :
1055 : : static void *
1056 : 2 : test_notify_handled_setup (PerformanceTest *test)
1057 : : {
1058 : : struct NotifyTest *data;
1059 : :
1060 : 2 : data = g_new0 (struct NotifyTest, 1);
1061 : 2 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1062 : :
1063 : 2 : g_signal_connect (data->object, "notify::val1",
1064 : : G_CALLBACK (test_notify_handled_handler), data);
1065 : 2 : g_signal_connect (data->object, "notify::val2",
1066 : : G_CALLBACK (test_notify_handled_handler), data);
1067 : :
1068 : 2 : return data;
1069 : : }
1070 : :
1071 : : static void
1072 : 14 : test_notify_handled_init (PerformanceTest *test,
1073 : : void *_data,
1074 : : double factor)
1075 : : {
1076 : 14 : struct NotifyTest *data = _data;
1077 : :
1078 : 14 : data->n_checks = factor * NUM_NOTIFY_PER_ROUND;
1079 : 14 : }
1080 : :
1081 : : static void
1082 : 14 : test_notify_handled_finish (PerformanceTest *test,
1083 : : void *data)
1084 : : {
1085 : 14 : }
1086 : :
1087 : : static void
1088 : 2 : test_notify_handled_print_result (PerformanceTest *test,
1089 : : void *_data,
1090 : : double time)
1091 : : {
1092 : 2 : struct NotifyTest *data = _data;
1093 : :
1094 : 2 : g_print ("Notify per second: %.0f\n",
1095 : 2 : data->n_checks / time);
1096 : 2 : }
1097 : :
1098 : : static void
1099 : 2 : test_notify_handled_teardown (PerformanceTest *test,
1100 : : void *_data)
1101 : : {
1102 : 2 : struct NotifyTest *data = _data;
1103 : :
1104 : 2 : g_assert_cmpuint (
1105 : : g_signal_handlers_disconnect_by_func (data->object,
1106 : : test_notify_handled_handler,
1107 : : data), ==, 2);
1108 : 2 : g_object_unref (data->object);
1109 : 2 : g_free (data);
1110 : 2 : }
1111 : :
1112 : : /*************************************************************
1113 : : * Test object set performance
1114 : : *************************************************************/
1115 : :
1116 : : #define NUM_SET_PER_ROUND 10000
1117 : :
1118 : : struct SetTest {
1119 : : GObject *object;
1120 : : unsigned n_checks;
1121 : : };
1122 : :
1123 : : static void
1124 : 7 : test_set_run (PerformanceTest *test,
1125 : : void *_data)
1126 : : {
1127 : 7 : struct SetTest *data = _data;
1128 : 7 : GObject *object = data->object;
1129 : :
1130 [ + + ]: 102925 : for (unsigned i = 0; i < data->n_checks; i++)
1131 : 102918 : g_object_set (object, "val1", i, NULL);
1132 : 7 : }
1133 : :
1134 : : static void *
1135 : 1 : test_set_setup (PerformanceTest *test)
1136 : : {
1137 : : struct SetTest *data;
1138 : :
1139 : 1 : data = g_new0 (struct SetTest, 1);
1140 : 1 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1141 : :
1142 : : /* g_object_get() will take a reference. Increasing the ref count from 1 to 2
1143 : : * is more expensive, due to the check for toggle notifications. We have a
1144 : : * performance test for that already. Don't also test that overhead during
1145 : : * "property-get" test and avoid this by taking an additional reference. */
1146 : 1 : g_object_ref (data->object);
1147 : :
1148 : 1 : return data;
1149 : : }
1150 : :
1151 : : static void
1152 : 7 : test_set_init (PerformanceTest *test,
1153 : : void *_data,
1154 : : double factor)
1155 : : {
1156 : 7 : struct SetTest *data = _data;
1157 : :
1158 : 7 : data->n_checks = factor * NUM_SET_PER_ROUND;
1159 : 7 : }
1160 : :
1161 : : static void
1162 : 7 : test_set_finish (PerformanceTest *test,
1163 : : void *data)
1164 : : {
1165 : 7 : }
1166 : :
1167 : : static void
1168 : 1 : test_set_print_result (PerformanceTest *test,
1169 : : void *_data,
1170 : : double time)
1171 : : {
1172 : 1 : struct SetTest *data = _data;
1173 : :
1174 : 1 : g_print ("Property set per second: %.0f\n",
1175 : 1 : data->n_checks / time);
1176 : 1 : }
1177 : :
1178 : : static void
1179 : 1 : test_set_teardown (PerformanceTest *test,
1180 : : void *_data)
1181 : : {
1182 : 1 : struct SetTest *data = _data;
1183 : :
1184 : 1 : g_object_unref (data->object);
1185 : 1 : g_object_unref (data->object);
1186 : 1 : g_free (data);
1187 : 1 : }
1188 : :
1189 : : /*************************************************************
1190 : : * Test object get performance
1191 : : *************************************************************/
1192 : :
1193 : : #define NUM_GET_PER_ROUND 10000
1194 : :
1195 : : struct GetTest {
1196 : : GObject *object;
1197 : : unsigned n_checks;
1198 : : };
1199 : :
1200 : : static void
1201 : 7 : test_get_run (PerformanceTest *test,
1202 : : void *_data)
1203 : : {
1204 : 7 : struct GetTest *data = _data;
1205 : 7 : GObject *object = data->object;
1206 : : int val;
1207 : :
1208 [ + + ]: 106276 : for (unsigned i = 0; i < data->n_checks; i++)
1209 : 106269 : g_object_get (object, "val1", &val, NULL);
1210 : 7 : }
1211 : :
1212 : : static void *
1213 : 1 : test_get_setup (PerformanceTest *test)
1214 : : {
1215 : : struct GetTest *data;
1216 : :
1217 : 1 : data = g_new0 (struct GetTest, 1);
1218 : 1 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1219 : :
1220 : : /* g_object_get() will take a reference. Increasing the ref count from 1 to 2
1221 : : * is more expensive, due to the check for toggle notifications. We have a
1222 : : * performance test for that already. Don't also test that overhead during
1223 : : * "property-get" test and avoid this by taking an additional reference. */
1224 : 1 : g_object_ref (data->object);
1225 : :
1226 : 1 : return data;
1227 : : }
1228 : :
1229 : : static void
1230 : 7 : test_get_init (PerformanceTest *test,
1231 : : void *_data,
1232 : : double factor)
1233 : : {
1234 : 7 : struct GetTest *data = _data;
1235 : :
1236 : 7 : data->n_checks = factor * NUM_GET_PER_ROUND;
1237 : 7 : }
1238 : :
1239 : : static void
1240 : 7 : test_get_finish (PerformanceTest *test,
1241 : : void *data)
1242 : : {
1243 : 7 : }
1244 : :
1245 : : static void
1246 : 1 : test_get_print_result (PerformanceTest *test,
1247 : : void *_data,
1248 : : double time)
1249 : : {
1250 : 1 : struct GetTest *data = _data;
1251 : :
1252 : 1 : g_print ("Property get per second: %.0f\n",
1253 : 1 : data->n_checks / time);
1254 : 1 : }
1255 : :
1256 : : static void
1257 : 1 : test_get_teardown (PerformanceTest *test,
1258 : : gpointer _data)
1259 : : {
1260 : 1 : struct GetTest *data = _data;
1261 : :
1262 : 1 : g_object_unref (data->object);
1263 : 1 : g_object_unref (data->object);
1264 : 1 : g_free (data);
1265 : 1 : }
1266 : :
1267 : : /*************************************************************
1268 : : * Test object refcount performance
1269 : : *************************************************************/
1270 : :
1271 : : #define NUM_KILO_REFS_PER_ROUND 100000
1272 : :
1273 : : struct RefcountTest {
1274 : : GObject *object;
1275 : : int n_checks;
1276 : : gboolean is_toggle_ref;
1277 : : };
1278 : :
1279 : : static void
1280 : 1232805 : test_refcount_toggle_ref_cb (gpointer data,
1281 : : GObject *object,
1282 : : gboolean is_last_ref)
1283 : : {
1284 : 1232805 : }
1285 : :
1286 : : static gpointer
1287 : 3 : test_refcount_setup (PerformanceTest *test)
1288 : : {
1289 : : struct RefcountTest *data;
1290 : :
1291 : 3 : data = g_new0 (struct RefcountTest, 1);
1292 : 3 : data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
1293 : :
1294 [ + + ]: 3 : if (g_str_equal (test->name, "refcount-toggle"))
1295 : : {
1296 : 1 : g_object_add_toggle_ref (data->object, test_refcount_toggle_ref_cb, NULL);
1297 : 1 : g_object_unref (data->object);
1298 : 1 : data->is_toggle_ref = TRUE;
1299 : : }
1300 : :
1301 : 3 : return data;
1302 : : }
1303 : :
1304 : : static void
1305 : 21 : test_refcount_init (PerformanceTest *test,
1306 : : gpointer _data,
1307 : : double factor)
1308 : : {
1309 : 21 : struct RefcountTest *data = _data;
1310 : :
1311 : 21 : data->n_checks = factor * NUM_KILO_REFS_PER_ROUND;
1312 : 21 : }
1313 : :
1314 : : static void
1315 : 7 : test_refcount_run (PerformanceTest *test,
1316 : : gpointer _data)
1317 : : {
1318 : 7 : struct RefcountTest *data = _data;
1319 : 7 : GObject *object = data->object;
1320 : : int i;
1321 : :
1322 [ + + ]: 622495 : for (i = 0; i < data->n_checks; i++)
1323 : : {
1324 : 622488 : g_object_ref (object);
1325 : 622488 : g_object_ref (object);
1326 : 622488 : g_object_ref (object);
1327 : 622488 : g_object_unref (object);
1328 : 622488 : g_object_unref (object);
1329 : :
1330 : 622488 : g_object_ref (object);
1331 : 622488 : g_object_ref (object);
1332 : 622488 : g_object_unref (object);
1333 : 622488 : g_object_unref (object);
1334 : 622488 : g_object_unref (object);
1335 : : }
1336 : 7 : }
1337 : :
1338 : : static void
1339 : 14 : test_refcount_1_run (PerformanceTest *test,
1340 : : gpointer _data)
1341 : : {
1342 : 14 : struct RefcountTest *data = _data;
1343 : 14 : GObject *object = data->object;
1344 : : int i;
1345 : :
1346 [ + + ]: 1264140 : for (i = 0; i < data->n_checks; i++)
1347 : : {
1348 : 1264126 : g_object_ref (object);
1349 : 1264126 : g_object_unref (object);
1350 : : }
1351 : 14 : }
1352 : :
1353 : : static void
1354 : 21 : test_refcount_finish (PerformanceTest *test,
1355 : : gpointer _data)
1356 : : {
1357 : 21 : }
1358 : :
1359 : : static void
1360 : 3 : test_refcount_print_result (PerformanceTest *test,
1361 : : gpointer _data,
1362 : : double time)
1363 : : {
1364 : 3 : struct RefcountTest *data = _data;
1365 : 3 : g_print ("Million refs+unref per second: %.2f\n",
1366 : 3 : data->n_checks * 5 / (time * 1000000 ));
1367 : 3 : }
1368 : :
1369 : : static void
1370 : 3 : test_refcount_teardown (PerformanceTest *test,
1371 : : gpointer _data)
1372 : : {
1373 : 3 : struct RefcountTest *data = _data;
1374 : :
1375 [ + + ]: 3 : if (data->is_toggle_ref)
1376 : 1 : g_object_remove_toggle_ref (data->object, test_refcount_toggle_ref_cb, NULL);
1377 : : else
1378 : 2 : g_object_unref (data->object);
1379 : :
1380 : 3 : g_free (data);
1381 : 3 : }
1382 : :
1383 : : /*************************************************************
1384 : : * Main test code
1385 : : *************************************************************/
1386 : :
1387 : : static PerformanceTest tests[] = {
1388 : : {
1389 : : "simple-construction",
1390 : : simple_object_get_type,
1391 : : test_construction_setup,
1392 : : test_construction_init,
1393 : : test_construction_run,
1394 : : test_construction_finish,
1395 : : test_construction_teardown,
1396 : : test_construction_print_result
1397 : : },
1398 : : {
1399 : : "simple-construction1",
1400 : : simple_object_get_type,
1401 : : test_construction_setup,
1402 : : test_construction_init,
1403 : : test_construction_run1,
1404 : : test_construction_finish1,
1405 : : test_construction_teardown,
1406 : : test_construction_print_result
1407 : : },
1408 : : {
1409 : : "complex-construction",
1410 : : complex_object_get_type,
1411 : : test_construction_setup,
1412 : : test_construction_init,
1413 : : test_complex_construction_run,
1414 : : test_construction_finish,
1415 : : test_construction_teardown,
1416 : : test_construction_print_result
1417 : : },
1418 : : {
1419 : : "complex-construction1",
1420 : : complex_object_get_type,
1421 : : test_construction_setup,
1422 : : test_construction_init,
1423 : : test_complex_construction_run1,
1424 : : test_construction_finish,
1425 : : test_construction_teardown,
1426 : : test_construction_print_result
1427 : : },
1428 : : {
1429 : : "complex-construction2",
1430 : : complex_object_get_type,
1431 : : test_construction_setup,
1432 : : test_construction_init,
1433 : : test_complex_construction_run2,
1434 : : test_construction_finish,
1435 : : test_construction_teardown,
1436 : : test_construction_print_result
1437 : : },
1438 : : {
1439 : : "finalization",
1440 : : simple_object_get_type,
1441 : : test_construction_setup,
1442 : : test_finalization_init,
1443 : : test_finalization_run,
1444 : : test_finalization_finish,
1445 : : test_construction_teardown,
1446 : : test_finalization_print_result
1447 : : },
1448 : : {
1449 : : "type-check",
1450 : : NULL,
1451 : : test_type_check_setup,
1452 : : test_type_check_init,
1453 : : test_type_check_run,
1454 : : test_type_check_finish,
1455 : : test_type_check_teardown,
1456 : : test_type_check_print_result
1457 : : },
1458 : : {
1459 : : "emit-unhandled",
1460 : : GINT_TO_POINTER (COMPLEX_SIGNAL),
1461 : : test_emission_unhandled_setup,
1462 : : test_emission_unhandled_init,
1463 : : test_emission_run,
1464 : : test_emission_unhandled_finish,
1465 : : test_emission_unhandled_teardown,
1466 : : test_emission_unhandled_print_result
1467 : : },
1468 : : {
1469 : : "emit-unhandled-empty",
1470 : : GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
1471 : : test_emission_unhandled_setup,
1472 : : test_emission_unhandled_init,
1473 : : test_emission_run,
1474 : : test_emission_unhandled_finish,
1475 : : test_emission_unhandled_teardown,
1476 : : test_emission_unhandled_print_result
1477 : : },
1478 : : {
1479 : : "emit-unhandled-generic",
1480 : : GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
1481 : : test_emission_unhandled_setup,
1482 : : test_emission_unhandled_init,
1483 : : test_emission_run,
1484 : : test_emission_unhandled_finish,
1485 : : test_emission_unhandled_teardown,
1486 : : test_emission_unhandled_print_result
1487 : : },
1488 : : {
1489 : : "emit-unhandled-generic-empty",
1490 : : GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
1491 : : test_emission_unhandled_setup,
1492 : : test_emission_unhandled_init,
1493 : : test_emission_run,
1494 : : test_emission_unhandled_finish,
1495 : : test_emission_unhandled_teardown,
1496 : : test_emission_unhandled_print_result
1497 : : },
1498 : : {
1499 : : "emit-unhandled-args",
1500 : : GINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
1501 : : test_emission_unhandled_setup,
1502 : : test_emission_unhandled_init,
1503 : : test_emission_run_args,
1504 : : test_emission_unhandled_finish,
1505 : : test_emission_unhandled_teardown,
1506 : : test_emission_unhandled_print_result
1507 : : },
1508 : : {
1509 : : "emit-handled",
1510 : : GINT_TO_POINTER (COMPLEX_SIGNAL),
1511 : : test_emission_handled_setup,
1512 : : test_emission_handled_init,
1513 : : test_emission_run,
1514 : : test_emission_handled_finish,
1515 : : test_emission_handled_teardown,
1516 : : test_emission_handled_print_result
1517 : : },
1518 : : {
1519 : : "emit-handled-empty",
1520 : : GINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
1521 : : test_emission_handled_setup,
1522 : : test_emission_handled_init,
1523 : : test_emission_run,
1524 : : test_emission_handled_finish,
1525 : : test_emission_handled_teardown,
1526 : : test_emission_handled_print_result
1527 : : },
1528 : : {
1529 : : "emit-handled-generic",
1530 : : GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
1531 : : test_emission_handled_setup,
1532 : : test_emission_handled_init,
1533 : : test_emission_run,
1534 : : test_emission_handled_finish,
1535 : : test_emission_handled_teardown,
1536 : : test_emission_handled_print_result
1537 : : },
1538 : : {
1539 : : "emit-handled-generic-empty",
1540 : : GINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
1541 : : test_emission_handled_setup,
1542 : : test_emission_handled_init,
1543 : : test_emission_run,
1544 : : test_emission_handled_finish,
1545 : : test_emission_handled_teardown,
1546 : : test_emission_handled_print_result
1547 : : },
1548 : : {
1549 : : "emit-handled-args",
1550 : : GINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
1551 : : test_emission_handled_setup,
1552 : : test_emission_handled_init,
1553 : : test_emission_run_args,
1554 : : test_emission_handled_finish,
1555 : : test_emission_handled_teardown,
1556 : : test_emission_handled_print_result
1557 : : },
1558 : : {
1559 : : "notify-unhandled",
1560 : : complex_object_get_type,
1561 : : test_notify_unhandled_setup,
1562 : : test_notify_unhandled_init,
1563 : : test_notify_run,
1564 : : test_notify_unhandled_finish,
1565 : : test_notify_unhandled_teardown,
1566 : : test_notify_unhandled_print_result
1567 : : },
1568 : : {
1569 : : "notify-by-pspec-unhandled",
1570 : : complex_object_get_type,
1571 : : test_notify_unhandled_setup,
1572 : : test_notify_unhandled_init,
1573 : : test_notify_by_pspec_run,
1574 : : test_notify_unhandled_finish,
1575 : : test_notify_unhandled_teardown,
1576 : : test_notify_unhandled_print_result
1577 : : },
1578 : : {
1579 : : "notify-handled",
1580 : : complex_object_get_type,
1581 : : test_notify_handled_setup,
1582 : : test_notify_handled_init,
1583 : : test_notify_run,
1584 : : test_notify_handled_finish,
1585 : : test_notify_handled_teardown,
1586 : : test_notify_handled_print_result
1587 : : },
1588 : : {
1589 : : "notify-by-pspec-handled",
1590 : : complex_object_get_type,
1591 : : test_notify_handled_setup,
1592 : : test_notify_handled_init,
1593 : : test_notify_by_pspec_run,
1594 : : test_notify_handled_finish,
1595 : : test_notify_handled_teardown,
1596 : : test_notify_handled_print_result
1597 : : },
1598 : : {
1599 : : "property-set",
1600 : : complex_object_get_type,
1601 : : test_set_setup,
1602 : : test_set_init,
1603 : : test_set_run,
1604 : : test_set_finish,
1605 : : test_set_teardown,
1606 : : test_set_print_result
1607 : : },
1608 : : {
1609 : : "property-get",
1610 : : complex_object_get_type,
1611 : : test_get_setup,
1612 : : test_get_init,
1613 : : test_get_run,
1614 : : test_get_finish,
1615 : : test_get_teardown,
1616 : : test_get_print_result
1617 : : },
1618 : : {
1619 : : "refcount",
1620 : : NULL,
1621 : : test_refcount_setup,
1622 : : test_refcount_init,
1623 : : test_refcount_run,
1624 : : test_refcount_finish,
1625 : : test_refcount_teardown,
1626 : : test_refcount_print_result
1627 : : },
1628 : : {
1629 : : "refcount-1",
1630 : : NULL,
1631 : : test_refcount_setup,
1632 : : test_refcount_init,
1633 : : test_refcount_1_run,
1634 : : test_refcount_finish,
1635 : : test_refcount_teardown,
1636 : : test_refcount_print_result
1637 : : },
1638 : : {
1639 : : "refcount-toggle",
1640 : : NULL,
1641 : : test_refcount_setup,
1642 : : test_refcount_init,
1643 : : test_refcount_1_run,
1644 : : test_refcount_finish,
1645 : : test_refcount_teardown,
1646 : : test_refcount_print_result
1647 : : },
1648 : : };
1649 : :
1650 : : static PerformanceTest *
1651 : 0 : find_test (const char *name)
1652 : : {
1653 : : gsize i;
1654 [ # # ]: 0 : for (i = 0; i < G_N_ELEMENTS (tests); i++)
1655 : : {
1656 [ # # ]: 0 : if (strcmp (tests[i].name, name) == 0)
1657 : 0 : return &tests[i];
1658 : : }
1659 : 0 : return NULL;
1660 : : }
1661 : : int
1662 : 1 : main (int argc,
1663 : : char *argv[])
1664 : : {
1665 : : PerformanceTest *test;
1666 : : GOptionContext *context;
1667 : 1 : GError *error = NULL;
1668 : : const char *str;
1669 : : int i;
1670 : :
1671 [ - + - - ]: 1 : if ((str = g_getenv ("GLIB_PERFORMANCE_FACTOR")) && str[0])
1672 : : {
1673 : 0 : test_factor = g_strtod (str, NULL);
1674 : : }
1675 : :
1676 : 1 : context = g_option_context_new ("GObject performance tests");
1677 : 1 : g_option_context_add_main_entries (context, cmd_entries, NULL);
1678 [ - + ]: 1 : if (!g_option_context_parse (context, &argc, &argv, &error))
1679 : : {
1680 : 0 : g_printerr ("%s: %s\n", argv[0], error->message);
1681 : 0 : return 1;
1682 : : }
1683 : :
1684 [ - + ]: 1 : if (test_factor < 0)
1685 : : {
1686 : 0 : g_printerr ("%s: test factor must be positive\n", argv[0]);
1687 : 0 : return 1;
1688 : : }
1689 : :
1690 : 1 : global_timer = g_timer_new ();
1691 : :
1692 [ - + ]: 1 : if (argc > 1)
1693 : : {
1694 [ # # ]: 0 : for (i = 1; i < argc; i++)
1695 : : {
1696 : 0 : test = find_test (argv[i]);
1697 [ # # ]: 0 : if (test)
1698 : 0 : run_test (test);
1699 : : }
1700 : : }
1701 : : else
1702 : : {
1703 : : gsize k;
1704 [ + + ]: 27 : for (k = 0; k < G_N_ELEMENTS (tests); k++)
1705 : 26 : run_test (&tests[k]);
1706 : : }
1707 : :
1708 : 1 : g_option_context_free (context);
1709 : 1 : g_clear_pointer (&global_timer, g_timer_destroy);
1710 : 1 : return 0;
1711 : : }
|