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