mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-26 15:36:14 +01:00
e35cfef509
If we enable `-Wfloat-conversion`, these warn about a possible loss of precision due to an implicit conversion from `double` to some other numeric type. The warning is correct: there is a possible loss of precision here. In these instances, we don’t care, as the floating point arithmetic is being done to do some imprecise scaling or imprecise timing. A loss of precision is not a problem. So, add an explicit cast to squash the warning. Signed-off-by: Philip Withnall <pwithnall@gnome.org> Helps: #3405
1702 lines
42 KiB
C
1702 lines
42 KiB
C
/* GObject - GLib Type, Object, Parameter and Signal Library
|
|
* Copyright (C) 2009 Red Hat, Inc.
|
|
* Copyright (C) 2022 Canonical Ltd.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <glib-object.h>
|
|
#include "../testcommon.h"
|
|
|
|
#define WARM_UP_N_RUNS 50
|
|
#define WARM_UP_ALWAYS_SEC 2.0
|
|
#define ESTIMATE_ROUND_TIME_N_RUNS 5
|
|
#define DEFAULT_TEST_TIME 15 /* seconds */
|
|
/* The time we want each round to take, in seconds, this should
|
|
* be large enough compared to the timer resolution, but small
|
|
* enough that the risk of any random slowness will miss the
|
|
* running window */
|
|
#define TARGET_ROUND_TIME 0.008
|
|
|
|
static gboolean verbose = FALSE;
|
|
static gboolean quiet = FALSE;
|
|
static int test_length = DEFAULT_TEST_TIME;
|
|
static double test_factor = 0;
|
|
static GTimer *global_timer = NULL;
|
|
|
|
static GOptionEntry cmd_entries[] = {
|
|
{"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
|
|
"Print extra information", NULL},
|
|
{"quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet,
|
|
"Print extra information", NULL},
|
|
{"seconds", 's', 0, G_OPTION_ARG_INT, &test_length,
|
|
"Time to run each test in seconds", NULL},
|
|
{"factor", 'f', 0, G_OPTION_ARG_DOUBLE, &test_factor,
|
|
"Use a fixed factor for sample runs (also $GLIB_PERFORMANCE_FACTOR)", NULL},
|
|
G_OPTION_ENTRY_NULL
|
|
};
|
|
|
|
typedef struct _PerformanceTest PerformanceTest;
|
|
struct _PerformanceTest {
|
|
const char *name;
|
|
gpointer extra_data;
|
|
|
|
gpointer (*setup) (PerformanceTest *test);
|
|
void (*init) (PerformanceTest *test,
|
|
gpointer data,
|
|
double factor);
|
|
void (*run) (PerformanceTest *test,
|
|
gpointer data);
|
|
void (*finish) (PerformanceTest *test,
|
|
gpointer data);
|
|
void (*teardown) (PerformanceTest *test,
|
|
gpointer data);
|
|
void (*print_result) (PerformanceTest *test,
|
|
gpointer data,
|
|
double time);
|
|
};
|
|
|
|
static void
|
|
run_test (PerformanceTest *test)
|
|
{
|
|
gpointer data = NULL;
|
|
guint64 i, num_rounds;
|
|
double elapsed, min_elapsed, max_elapsed, avg_elapsed, factor;
|
|
GTimer *timer;
|
|
|
|
if (verbose || !quiet)
|
|
g_print ("Running test %s\n", test->name);
|
|
|
|
/* Set up test */
|
|
timer = g_timer_new ();
|
|
data = test->setup (test);
|
|
|
|
if (verbose)
|
|
g_print ("Warming up\n");
|
|
|
|
g_timer_start (timer);
|
|
|
|
/* Warm up the test by doing a few runs */
|
|
for (i = 0; TRUE; i++)
|
|
{
|
|
test->init (test, data, 1.0);
|
|
test->run (test, data);
|
|
test->finish (test, data);
|
|
|
|
if (test_factor > 0)
|
|
{
|
|
/* The caller specified a constant factor. That makes mostly
|
|
* sense, to ensure that the test run is independent from
|
|
* external factors. In this case, don't make warm up dependent
|
|
* on WARM_UP_ALWAYS_SEC. */
|
|
}
|
|
else if (global_timer)
|
|
{
|
|
if (g_timer_elapsed (global_timer, NULL) < WARM_UP_ALWAYS_SEC)
|
|
{
|
|
/* We always warm up for a certain time where we keep the
|
|
* CPU busy.
|
|
*
|
|
* Note that when we run multiple tests, then this is only
|
|
* performed once for the first test. */
|
|
continue;
|
|
}
|
|
g_clear_pointer (&global_timer, g_timer_destroy);
|
|
}
|
|
|
|
if (i >= WARM_UP_N_RUNS)
|
|
break;
|
|
|
|
if (test_factor == 0 && g_timer_elapsed (timer, NULL) > test_length / 10)
|
|
{
|
|
/* The warm up should not take longer than 10 % of the entire
|
|
* test run. Note that the warm up time for WARM_UP_ALWAYS_SEC
|
|
* already passed. */
|
|
break;
|
|
}
|
|
}
|
|
|
|
g_timer_stop (timer);
|
|
elapsed = g_timer_elapsed (timer, NULL);
|
|
|
|
if (verbose)
|
|
{
|
|
g_print ("Warm up time: %.2f secs\n", elapsed);
|
|
g_print ("Estimating round time\n");
|
|
}
|
|
|
|
min_elapsed = 0;
|
|
|
|
if (test_factor > 0)
|
|
{
|
|
factor = test_factor;
|
|
}
|
|
else
|
|
{
|
|
/* Estimate time for one run by doing a few test rounds. */
|
|
for (i = 0; i < ESTIMATE_ROUND_TIME_N_RUNS; i++)
|
|
{
|
|
test->init (test, data, 1.0);
|
|
g_timer_start (timer);
|
|
test->run (test, data);
|
|
g_timer_stop (timer);
|
|
test->finish (test, data);
|
|
|
|
elapsed = g_timer_elapsed (timer, NULL);
|
|
if (i == 0)
|
|
min_elapsed = elapsed;
|
|
else
|
|
min_elapsed = MIN (min_elapsed, elapsed);
|
|
}
|
|
|
|
factor = TARGET_ROUND_TIME / min_elapsed;
|
|
}
|
|
|
|
if (verbose)
|
|
g_print ("Uncorrected round time: %.4f msecs, correction factor %.2f\n", 1000*min_elapsed, factor);
|
|
|
|
/* Calculate number of rounds needed */
|
|
num_rounds = (guint64) (test_length / TARGET_ROUND_TIME) + 1;
|
|
|
|
if (verbose)
|
|
g_print ("Running %"G_GINT64_MODIFIER"d rounds\n", num_rounds);
|
|
|
|
/* Run the test */
|
|
avg_elapsed = 0.0;
|
|
min_elapsed = 1e100;
|
|
max_elapsed = 0.0;
|
|
for (i = 0; i < num_rounds; i++)
|
|
{
|
|
test->init (test, data, factor);
|
|
g_timer_start (timer);
|
|
test->run (test, data);
|
|
g_timer_stop (timer);
|
|
test->finish (test, data);
|
|
|
|
if (i < num_rounds / 20)
|
|
{
|
|
/* The first 5% are additional warm up. Ignore. */
|
|
continue;
|
|
}
|
|
|
|
elapsed = g_timer_elapsed (timer, NULL);
|
|
|
|
min_elapsed = MIN (min_elapsed, elapsed);
|
|
max_elapsed = MAX (max_elapsed, elapsed);
|
|
avg_elapsed += elapsed;
|
|
}
|
|
|
|
if (num_rounds > 1)
|
|
avg_elapsed = avg_elapsed / num_rounds;
|
|
|
|
if (verbose)
|
|
{
|
|
g_print ("Minimum corrected round time: %.2f msecs\n", min_elapsed * 1000);
|
|
g_print ("Maximum corrected round time: %.2f msecs\n", max_elapsed * 1000);
|
|
g_print ("Average corrected round time: %.2f msecs\n", avg_elapsed * 1000);
|
|
}
|
|
|
|
/* Print the results */
|
|
g_print ("%s: ", test->name);
|
|
test->print_result (test, data, min_elapsed);
|
|
|
|
/* Tear down */
|
|
test->teardown (test, data);
|
|
g_timer_destroy (timer);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Simple object is a very simple small GObject subclass
|
|
* with no properties, no signals, implementing no interfaces
|
|
*************************************************************/
|
|
|
|
static GType simple_object_get_type (void);
|
|
#define SIMPLE_TYPE_OBJECT (simple_object_get_type ())
|
|
typedef struct _SimpleObject SimpleObject;
|
|
typedef struct _SimpleObjectClass SimpleObjectClass;
|
|
|
|
struct _SimpleObject
|
|
{
|
|
GObject parent_instance;
|
|
int val;
|
|
};
|
|
|
|
struct _SimpleObjectClass
|
|
{
|
|
GObjectClass parent_class;
|
|
};
|
|
|
|
G_DEFINE_TYPE (SimpleObject, simple_object, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
simple_object_finalize (GObject *object)
|
|
{
|
|
G_OBJECT_CLASS (simple_object_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
simple_object_class_init (SimpleObjectClass *class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
object_class->finalize = simple_object_finalize;
|
|
}
|
|
|
|
static void
|
|
simple_object_init (SimpleObject *simple_object)
|
|
{
|
|
simple_object->val = 42;
|
|
}
|
|
|
|
typedef struct _TestIfaceClass TestIfaceClass;
|
|
typedef struct _TestIfaceClass TestIface1Class;
|
|
typedef struct _TestIfaceClass TestIface2Class;
|
|
typedef struct _TestIfaceClass TestIface3Class;
|
|
typedef struct _TestIfaceClass TestIface4Class;
|
|
typedef struct _TestIfaceClass TestIface5Class;
|
|
typedef struct _TestIface TestIface;
|
|
|
|
struct _TestIfaceClass
|
|
{
|
|
GTypeInterface base_iface;
|
|
void (*method) (TestIface *obj);
|
|
};
|
|
|
|
static GType test_iface1_get_type (void);
|
|
static GType test_iface2_get_type (void);
|
|
static GType test_iface3_get_type (void);
|
|
static GType test_iface4_get_type (void);
|
|
static GType test_iface5_get_type (void);
|
|
|
|
#define TEST_TYPE_IFACE1 (test_iface1_get_type ())
|
|
#define TEST_TYPE_IFACE2 (test_iface2_get_type ())
|
|
#define TEST_TYPE_IFACE3 (test_iface3_get_type ())
|
|
#define TEST_TYPE_IFACE4 (test_iface4_get_type ())
|
|
#define TEST_TYPE_IFACE5 (test_iface5_get_type ())
|
|
|
|
static DEFINE_IFACE (TestIface1, test_iface1, NULL, NULL)
|
|
static DEFINE_IFACE (TestIface2, test_iface2, NULL, NULL)
|
|
static DEFINE_IFACE (TestIface3, test_iface3, NULL, NULL)
|
|
static DEFINE_IFACE (TestIface4, test_iface4, NULL, NULL)
|
|
static DEFINE_IFACE (TestIface5, test_iface5, NULL, NULL)
|
|
|
|
/*************************************************************
|
|
* Complex object is a GObject subclass with a properties,
|
|
* construct properties, signals and implementing an interface.
|
|
*************************************************************/
|
|
|
|
static GType complex_object_get_type (void);
|
|
#define COMPLEX_TYPE_OBJECT (complex_object_get_type ())
|
|
typedef struct _ComplexObject ComplexObject;
|
|
typedef struct _ComplexObjectClass ComplexObjectClass;
|
|
|
|
struct _ComplexObject
|
|
{
|
|
GObject parent_instance;
|
|
int val1;
|
|
char *val2;
|
|
};
|
|
|
|
struct _ComplexObjectClass
|
|
{
|
|
GObjectClass parent_class;
|
|
|
|
void (*signal) (ComplexObject *obj);
|
|
void (*signal_empty) (ComplexObject *obj);
|
|
};
|
|
|
|
static void complex_test_iface_init (gpointer g_iface,
|
|
gpointer iface_data);
|
|
|
|
G_DEFINE_TYPE_EXTENDED (ComplexObject, complex_object,
|
|
G_TYPE_OBJECT, 0,
|
|
G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE1, complex_test_iface_init)
|
|
G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE2, complex_test_iface_init)
|
|
G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE3, complex_test_iface_init)
|
|
G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE4, complex_test_iface_init)
|
|
G_IMPLEMENT_INTERFACE (TEST_TYPE_IFACE5, complex_test_iface_init))
|
|
|
|
#define COMPLEX_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), COMPLEX_TYPE_OBJECT, ComplexObject))
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_VAL1,
|
|
PROP_VAL2,
|
|
N_PROPERTIES
|
|
};
|
|
|
|
static GParamSpec *pspecs[N_PROPERTIES] = { NULL, };
|
|
|
|
enum {
|
|
COMPLEX_SIGNAL,
|
|
COMPLEX_SIGNAL_EMPTY,
|
|
COMPLEX_SIGNAL_GENERIC,
|
|
COMPLEX_SIGNAL_GENERIC_EMPTY,
|
|
COMPLEX_SIGNAL_ARGS,
|
|
COMPLEX_LAST_SIGNAL
|
|
};
|
|
|
|
static guint complex_signals[COMPLEX_LAST_SIGNAL] = { 0 };
|
|
|
|
static void
|
|
complex_object_finalize (GObject *object)
|
|
{
|
|
ComplexObject *c = COMPLEX_OBJECT (object);
|
|
|
|
g_free (c->val2);
|
|
|
|
G_OBJECT_CLASS (complex_object_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
complex_object_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ComplexObject *complex = COMPLEX_OBJECT (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_VAL1:
|
|
complex->val1 = g_value_get_int (value);
|
|
break;
|
|
case PROP_VAL2:
|
|
g_free (complex->val2);
|
|
complex->val2 = g_value_dup_string (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
complex_object_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
ComplexObject *complex = COMPLEX_OBJECT (object);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_VAL1:
|
|
g_value_set_int (value, complex->val1);
|
|
break;
|
|
case PROP_VAL2:
|
|
g_value_set_string (value, complex->val2);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
complex_object_real_signal (ComplexObject *obj)
|
|
{
|
|
}
|
|
|
|
static void
|
|
complex_object_class_init (ComplexObjectClass *class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
|
|
|
object_class->finalize = complex_object_finalize;
|
|
object_class->set_property = complex_object_set_property;
|
|
object_class->get_property = complex_object_get_property;
|
|
|
|
class->signal = complex_object_real_signal;
|
|
|
|
complex_signals[COMPLEX_SIGNAL] =
|
|
g_signal_new ("signal",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ComplexObjectClass, signal),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
complex_signals[COMPLEX_SIGNAL_EMPTY] =
|
|
g_signal_new ("signal-empty",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE, 0);
|
|
|
|
complex_signals[COMPLEX_SIGNAL_GENERIC] =
|
|
g_signal_new ("signal-generic",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ComplexObjectClass, signal),
|
|
NULL, NULL,
|
|
NULL,
|
|
G_TYPE_NONE, 0);
|
|
complex_signals[COMPLEX_SIGNAL_GENERIC_EMPTY] =
|
|
g_signal_new ("signal-generic-empty",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ComplexObjectClass, signal_empty),
|
|
NULL, NULL,
|
|
NULL,
|
|
G_TYPE_NONE, 0);
|
|
|
|
complex_signals[COMPLEX_SIGNAL_ARGS] =
|
|
g_signal_new ("signal-args",
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
G_SIGNAL_RUN_FIRST,
|
|
G_STRUCT_OFFSET (ComplexObjectClass, signal),
|
|
NULL, NULL,
|
|
g_cclosure_marshal_VOID__UINT_POINTER,
|
|
G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_POINTER);
|
|
|
|
pspecs[PROP_VAL1] = g_param_spec_int ("val1", "val1", "val1",
|
|
0, G_MAXINT, 42,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
|
|
pspecs[PROP_VAL2] = g_param_spec_string ("val2", "val2", "val2",
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPERTIES, pspecs);
|
|
}
|
|
|
|
static void
|
|
complex_object_iface_method (TestIface *obj)
|
|
{
|
|
ComplexObject *complex = COMPLEX_OBJECT (obj);
|
|
complex->val1++;
|
|
}
|
|
|
|
static void
|
|
complex_test_iface_init (gpointer g_iface,
|
|
gpointer iface_data)
|
|
{
|
|
TestIfaceClass *iface = g_iface;
|
|
iface->method = complex_object_iface_method;
|
|
}
|
|
|
|
static void
|
|
complex_object_init (ComplexObject *complex_object)
|
|
{
|
|
complex_object->val1 = 42;
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test object construction performance
|
|
*************************************************************/
|
|
|
|
#define NUM_OBJECT_TO_CONSTRUCT 10000
|
|
|
|
struct ConstructionTest {
|
|
GObject **objects;
|
|
unsigned int n_objects;
|
|
GType type;
|
|
};
|
|
|
|
static gpointer
|
|
test_construction_setup (PerformanceTest *test)
|
|
{
|
|
struct ConstructionTest *data;
|
|
|
|
data = g_new0 (struct ConstructionTest, 1);
|
|
data->type = ((GType (*)(void))test->extra_data)();
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_construction_init (PerformanceTest *test,
|
|
gpointer _data,
|
|
double count_factor)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
unsigned int n;
|
|
|
|
n = (unsigned int) (NUM_OBJECT_TO_CONSTRUCT * count_factor);
|
|
if (data->n_objects != n)
|
|
{
|
|
data->n_objects = n;
|
|
data->objects = g_renew (GObject *, data->objects, n);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_construction_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
GObject **objects = data->objects;
|
|
GType type = data->type;
|
|
unsigned int n_objects;
|
|
|
|
n_objects = data->n_objects;
|
|
for (unsigned int i = 0; i < n_objects; i++)
|
|
objects[i] = g_object_new (type, NULL);
|
|
}
|
|
|
|
static void
|
|
test_construction_run1 (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
GObject **objects = data->objects;
|
|
unsigned int n_objects;
|
|
|
|
n_objects = data->n_objects;
|
|
for (unsigned int i = 0; i < n_objects; i++)
|
|
objects[i] = (GObject *) g_slice_new0 (SimpleObject);
|
|
}
|
|
|
|
static void
|
|
test_complex_construction_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
GObject **objects = data->objects;
|
|
GType type = data->type;
|
|
unsigned int n_objects;
|
|
|
|
n_objects = data->n_objects;
|
|
for (unsigned int i = 0; i < n_objects; i++)
|
|
objects[i] = g_object_new (type, "val1", 5, "val2", "thousand", NULL);
|
|
}
|
|
|
|
static void
|
|
test_complex_construction_run1 (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
GObject **objects = data->objects;
|
|
GType type = data->type;
|
|
unsigned int n_objects;
|
|
|
|
n_objects = data->n_objects;
|
|
for (unsigned int i = 0; i < n_objects; i++)
|
|
{
|
|
ComplexObject *object;
|
|
object = (ComplexObject *)g_object_new (type, NULL);
|
|
object->val1 = 5;
|
|
object->val2 = g_strdup ("thousand");
|
|
objects[i] = (GObject *)object;
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_complex_construction_run2 (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
GObject **objects = data->objects;
|
|
GType type = data->type;
|
|
unsigned int n_objects;
|
|
|
|
n_objects = data->n_objects;
|
|
for (unsigned int i = 0; i < n_objects; i++)
|
|
{
|
|
objects[i] = g_object_new (type, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_construction_finish (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
|
|
for (unsigned int i = 0; i < data->n_objects; i++)
|
|
g_object_unref (data->objects[i]);
|
|
}
|
|
|
|
static void
|
|
test_construction_finish1 (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
|
|
for (unsigned int i = 0; i < data->n_objects; i++)
|
|
g_slice_free (SimpleObject, (SimpleObject *)data->objects[i]);
|
|
}
|
|
|
|
static void
|
|
test_construction_teardown (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
g_free (data->objects);
|
|
g_free (data);
|
|
}
|
|
|
|
static void
|
|
test_finalization_init (PerformanceTest *test,
|
|
gpointer _data,
|
|
double count_factor)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
unsigned int n;
|
|
|
|
n = (unsigned int) (NUM_OBJECT_TO_CONSTRUCT * count_factor);
|
|
if (data->n_objects != n)
|
|
{
|
|
data->n_objects = n;
|
|
data->objects = g_renew (GObject *, data->objects, n);
|
|
}
|
|
|
|
for (unsigned int i = 0; i < data->n_objects; i++)
|
|
{
|
|
data->objects[i] = g_object_new (data->type, NULL);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_finalization_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
GObject **objects = data->objects;
|
|
unsigned int n_objects;
|
|
|
|
n_objects = data->n_objects;
|
|
for (unsigned int i = 0; i < n_objects; i++)
|
|
{
|
|
g_object_unref (objects[i]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_finalization_finish (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_construction_print_result (PerformanceTest *test,
|
|
gpointer _data,
|
|
double time)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
|
|
g_print ("Millions of constructed objects per second: %.3f\n",
|
|
data->n_objects / (time * 1000000));
|
|
}
|
|
|
|
static void
|
|
test_finalization_print_result (PerformanceTest *test,
|
|
gpointer _data,
|
|
double time)
|
|
{
|
|
struct ConstructionTest *data = _data;
|
|
|
|
g_print ("Millions of finalized objects per second: %.3f\n",
|
|
data->n_objects / (time * 1000000));
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test runtime type check performance
|
|
*************************************************************/
|
|
|
|
#define NUM_KILO_CHECKS_PER_ROUND 50
|
|
|
|
struct TypeCheckTest {
|
|
GObject *object;
|
|
unsigned int n_checks;
|
|
};
|
|
|
|
static gpointer
|
|
test_type_check_setup (PerformanceTest *test)
|
|
{
|
|
struct TypeCheckTest *data;
|
|
|
|
data = g_new0 (struct TypeCheckTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_type_check_init (PerformanceTest *test,
|
|
gpointer _data,
|
|
double factor)
|
|
{
|
|
struct TypeCheckTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_KILO_CHECKS_PER_ROUND);
|
|
}
|
|
|
|
|
|
/* Work around g_type_check_instance_is_a being marked "pure",
|
|
and thus only called once for the loop. */
|
|
gboolean (*my_type_check_instance_is_a) (GTypeInstance *type_instance,
|
|
GType iface_type) = &g_type_check_instance_is_a;
|
|
|
|
static void
|
|
test_type_check_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct TypeCheckTest *data = _data;
|
|
GObject *object = data->object;
|
|
GType type, types[5];
|
|
|
|
types[0] = test_iface1_get_type ();
|
|
types[1] = test_iface2_get_type ();
|
|
types[2] = test_iface3_get_type ();
|
|
types[3] = test_iface4_get_type ();
|
|
types[4] = test_iface5_get_type ();
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
{
|
|
type = types[i%5];
|
|
for (unsigned int j = 0; j < 1000; j++)
|
|
{
|
|
my_type_check_instance_is_a ((GTypeInstance *)object,
|
|
type);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_type_check_finish (PerformanceTest *test,
|
|
gpointer data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_type_check_print_result (PerformanceTest *test,
|
|
gpointer _data,
|
|
double time)
|
|
{
|
|
struct TypeCheckTest *data = _data;
|
|
g_print ("Million type checks per second: %.2f\n",
|
|
data->n_checks / (1000*time));
|
|
}
|
|
|
|
static void
|
|
test_type_check_teardown (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct TypeCheckTest *data = _data;
|
|
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test signal emissions performance (common code)
|
|
*************************************************************/
|
|
|
|
#define NUM_EMISSIONS_PER_ROUND 10000
|
|
|
|
struct EmissionTest {
|
|
GObject *object;
|
|
unsigned int n_checks;
|
|
unsigned int signal_id;
|
|
};
|
|
|
|
static void
|
|
test_emission_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
g_signal_emit (object, data->signal_id, 0);
|
|
}
|
|
|
|
static void
|
|
test_emission_run_args (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
g_signal_emit (object, data->signal_id, 0, 0, NULL);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test signal unhandled emissions performance
|
|
*************************************************************/
|
|
|
|
static gpointer
|
|
test_emission_unhandled_setup (PerformanceTest *test)
|
|
{
|
|
struct EmissionTest *data;
|
|
|
|
data = g_new0 (struct EmissionTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
data->signal_id = complex_signals[GPOINTER_TO_UINT (test->extra_data)];
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_emission_unhandled_init (PerformanceTest *test,
|
|
gpointer _data,
|
|
double factor)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_EMISSIONS_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_emission_unhandled_finish (PerformanceTest *test,
|
|
gpointer data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_emission_unhandled_print_result (PerformanceTest *test,
|
|
gpointer _data,
|
|
double time)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
|
|
g_print ("Emissions per second: %.0f\n",
|
|
data->n_checks / time);
|
|
}
|
|
|
|
static void
|
|
test_emission_unhandled_teardown (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test signal handled emissions performance
|
|
*************************************************************/
|
|
|
|
static void
|
|
test_emission_handled_handler (ComplexObject *obj, gpointer data)
|
|
{
|
|
}
|
|
|
|
static gpointer
|
|
test_emission_handled_setup (PerformanceTest *test)
|
|
{
|
|
struct EmissionTest *data;
|
|
|
|
data = g_new0 (struct EmissionTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
data->signal_id = complex_signals[GPOINTER_TO_UINT (test->extra_data)];
|
|
g_signal_connect (data->object, "signal",
|
|
G_CALLBACK (test_emission_handled_handler),
|
|
NULL);
|
|
g_signal_connect (data->object, "signal-empty",
|
|
G_CALLBACK (test_emission_handled_handler),
|
|
NULL);
|
|
g_signal_connect (data->object, "signal-generic",
|
|
G_CALLBACK (test_emission_handled_handler),
|
|
NULL);
|
|
g_signal_connect (data->object, "signal-generic-empty",
|
|
G_CALLBACK (test_emission_handled_handler),
|
|
NULL);
|
|
g_signal_connect (data->object, "signal-args",
|
|
G_CALLBACK (test_emission_handled_handler),
|
|
NULL);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_emission_handled_init (PerformanceTest *test,
|
|
gpointer _data,
|
|
double factor)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_EMISSIONS_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_emission_handled_finish (PerformanceTest *test,
|
|
gpointer data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_emission_handled_print_result (PerformanceTest *test,
|
|
gpointer _data,
|
|
double time)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
|
|
g_print ("Emissions per second: %.0f\n",
|
|
data->n_checks / time);
|
|
}
|
|
|
|
static void
|
|
test_emission_handled_teardown (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct EmissionTest *data = _data;
|
|
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test object notify performance (common code)
|
|
*************************************************************/
|
|
|
|
#define NUM_NOTIFY_PER_ROUND 10000
|
|
|
|
struct NotifyTest {
|
|
GObject *object;
|
|
unsigned int n_checks;
|
|
};
|
|
|
|
static void
|
|
test_notify_run (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
g_object_notify (object, "val1");
|
|
}
|
|
|
|
static void
|
|
test_notify_by_pspec_run (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
g_object_notify_by_pspec (object, pspecs[PROP_VAL1]);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test notify unhandled performance
|
|
*************************************************************/
|
|
|
|
static void *
|
|
test_notify_unhandled_setup (PerformanceTest *test)
|
|
{
|
|
struct NotifyTest *data;
|
|
|
|
data = g_new0 (struct NotifyTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_notify_unhandled_init (PerformanceTest *test,
|
|
void *_data,
|
|
double factor)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_NOTIFY_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_notify_unhandled_finish (PerformanceTest *test,
|
|
void *data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_notify_unhandled_print_result (PerformanceTest *test,
|
|
void *_data,
|
|
double time)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
|
|
g_print ("Notify (unhandled) per second: %.0f\n",
|
|
data->n_checks / time);
|
|
}
|
|
|
|
static void
|
|
test_notify_unhandled_teardown (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test notify handled performance
|
|
*************************************************************/
|
|
|
|
static void
|
|
test_notify_handled_handler (ComplexObject *obj, GParamSpec *pspec, void *data)
|
|
{
|
|
}
|
|
|
|
static void *
|
|
test_notify_handled_setup (PerformanceTest *test)
|
|
{
|
|
struct NotifyTest *data;
|
|
|
|
data = g_new0 (struct NotifyTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
|
|
g_signal_connect (data->object, "notify::val1",
|
|
G_CALLBACK (test_notify_handled_handler), data);
|
|
g_signal_connect (data->object, "notify::val2",
|
|
G_CALLBACK (test_notify_handled_handler), data);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_notify_handled_init (PerformanceTest *test,
|
|
void *_data,
|
|
double factor)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_NOTIFY_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_notify_handled_finish (PerformanceTest *test,
|
|
void *data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_notify_handled_print_result (PerformanceTest *test,
|
|
void *_data,
|
|
double time)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
|
|
g_print ("Notify per second: %.0f\n",
|
|
data->n_checks / time);
|
|
}
|
|
|
|
static void
|
|
test_notify_handled_teardown (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct NotifyTest *data = _data;
|
|
|
|
g_assert_cmpuint (
|
|
g_signal_handlers_disconnect_by_func (data->object,
|
|
test_notify_handled_handler,
|
|
data), ==, 2);
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test object set performance
|
|
*************************************************************/
|
|
|
|
#define NUM_SET_PER_ROUND 10000
|
|
|
|
struct SetTest {
|
|
GObject *object;
|
|
unsigned int n_checks;
|
|
};
|
|
|
|
static void
|
|
test_set_run (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct SetTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
g_object_set (object, "val1", i, NULL);
|
|
}
|
|
|
|
static void *
|
|
test_set_setup (PerformanceTest *test)
|
|
{
|
|
struct SetTest *data;
|
|
|
|
data = g_new0 (struct SetTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
|
|
/* g_object_get() will take a reference. Increasing the ref count from 1 to 2
|
|
* is more expensive, due to the check for toggle notifications. We have a
|
|
* performance test for that already. Don't also test that overhead during
|
|
* "property-get" test and avoid this by taking an additional reference. */
|
|
g_object_ref (data->object);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_set_init (PerformanceTest *test,
|
|
void *_data,
|
|
double factor)
|
|
{
|
|
struct SetTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_SET_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_set_finish (PerformanceTest *test,
|
|
void *data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_set_print_result (PerformanceTest *test,
|
|
void *_data,
|
|
double time)
|
|
{
|
|
struct SetTest *data = _data;
|
|
|
|
g_print ("Property set per second: %.0f\n",
|
|
data->n_checks / time);
|
|
}
|
|
|
|
static void
|
|
test_set_teardown (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct SetTest *data = _data;
|
|
|
|
g_object_unref (data->object);
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test object get performance
|
|
*************************************************************/
|
|
|
|
#define NUM_GET_PER_ROUND 10000
|
|
|
|
struct GetTest {
|
|
GObject *object;
|
|
unsigned int n_checks;
|
|
};
|
|
|
|
static void
|
|
test_get_run (PerformanceTest *test,
|
|
void *_data)
|
|
{
|
|
struct GetTest *data = _data;
|
|
GObject *object = data->object;
|
|
int val;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
g_object_get (object, "val1", &val, NULL);
|
|
}
|
|
|
|
static void *
|
|
test_get_setup (PerformanceTest *test)
|
|
{
|
|
struct GetTest *data;
|
|
|
|
data = g_new0 (struct GetTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
|
|
/* g_object_get() will take a reference. Increasing the ref count from 1 to 2
|
|
* is more expensive, due to the check for toggle notifications. We have a
|
|
* performance test for that already. Don't also test that overhead during
|
|
* "property-get" test and avoid this by taking an additional reference. */
|
|
g_object_ref (data->object);
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_get_init (PerformanceTest *test,
|
|
void *_data,
|
|
double factor)
|
|
{
|
|
struct GetTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_GET_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_get_finish (PerformanceTest *test,
|
|
void *data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_get_print_result (PerformanceTest *test,
|
|
void *_data,
|
|
double time)
|
|
{
|
|
struct GetTest *data = _data;
|
|
|
|
g_print ("Property get per second: %.0f\n",
|
|
data->n_checks / time);
|
|
}
|
|
|
|
static void
|
|
test_get_teardown (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct GetTest *data = _data;
|
|
|
|
g_object_unref (data->object);
|
|
g_object_unref (data->object);
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Test object refcount performance
|
|
*************************************************************/
|
|
|
|
#define NUM_KILO_REFS_PER_ROUND 100000
|
|
|
|
struct RefcountTest {
|
|
GObject *object;
|
|
unsigned int n_checks;
|
|
gboolean is_toggle_ref;
|
|
};
|
|
|
|
static void
|
|
test_refcount_toggle_ref_cb (gpointer data,
|
|
GObject *object,
|
|
gboolean is_last_ref)
|
|
{
|
|
}
|
|
|
|
static gpointer
|
|
test_refcount_setup (PerformanceTest *test)
|
|
{
|
|
struct RefcountTest *data;
|
|
|
|
data = g_new0 (struct RefcountTest, 1);
|
|
data->object = g_object_new (COMPLEX_TYPE_OBJECT, NULL);
|
|
|
|
if (g_str_equal (test->name, "refcount-toggle"))
|
|
{
|
|
g_object_add_toggle_ref (data->object, test_refcount_toggle_ref_cb, NULL);
|
|
g_object_unref (data->object);
|
|
data->is_toggle_ref = TRUE;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
static void
|
|
test_refcount_init (PerformanceTest *test,
|
|
gpointer _data,
|
|
double factor)
|
|
{
|
|
struct RefcountTest *data = _data;
|
|
|
|
data->n_checks = (unsigned int) (factor * NUM_KILO_REFS_PER_ROUND);
|
|
}
|
|
|
|
static void
|
|
test_refcount_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct RefcountTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
{
|
|
g_object_ref (object);
|
|
g_object_ref (object);
|
|
g_object_ref (object);
|
|
g_object_unref (object);
|
|
g_object_unref (object);
|
|
|
|
g_object_ref (object);
|
|
g_object_ref (object);
|
|
g_object_unref (object);
|
|
g_object_unref (object);
|
|
g_object_unref (object);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_refcount_1_run (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct RefcountTest *data = _data;
|
|
GObject *object = data->object;
|
|
|
|
for (unsigned int i = 0; i < data->n_checks; i++)
|
|
{
|
|
g_object_ref (object);
|
|
g_object_unref (object);
|
|
}
|
|
}
|
|
|
|
static void
|
|
test_refcount_finish (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
}
|
|
|
|
static void
|
|
test_refcount_print_result (PerformanceTest *test,
|
|
gpointer _data,
|
|
double time)
|
|
{
|
|
struct RefcountTest *data = _data;
|
|
g_print ("Million refs+unref per second: %.2f\n",
|
|
data->n_checks * 5 / (time * 1000000 ));
|
|
}
|
|
|
|
static void
|
|
test_refcount_teardown (PerformanceTest *test,
|
|
gpointer _data)
|
|
{
|
|
struct RefcountTest *data = _data;
|
|
|
|
if (data->is_toggle_ref)
|
|
g_object_remove_toggle_ref (data->object, test_refcount_toggle_ref_cb, NULL);
|
|
else
|
|
g_object_unref (data->object);
|
|
|
|
g_free (data);
|
|
}
|
|
|
|
/*************************************************************
|
|
* Main test code
|
|
*************************************************************/
|
|
|
|
static PerformanceTest tests[] = {
|
|
{
|
|
"simple-construction",
|
|
simple_object_get_type,
|
|
test_construction_setup,
|
|
test_construction_init,
|
|
test_construction_run,
|
|
test_construction_finish,
|
|
test_construction_teardown,
|
|
test_construction_print_result
|
|
},
|
|
{
|
|
"simple-construction1",
|
|
simple_object_get_type,
|
|
test_construction_setup,
|
|
test_construction_init,
|
|
test_construction_run1,
|
|
test_construction_finish1,
|
|
test_construction_teardown,
|
|
test_construction_print_result
|
|
},
|
|
{
|
|
"complex-construction",
|
|
complex_object_get_type,
|
|
test_construction_setup,
|
|
test_construction_init,
|
|
test_complex_construction_run,
|
|
test_construction_finish,
|
|
test_construction_teardown,
|
|
test_construction_print_result
|
|
},
|
|
{
|
|
"complex-construction1",
|
|
complex_object_get_type,
|
|
test_construction_setup,
|
|
test_construction_init,
|
|
test_complex_construction_run1,
|
|
test_construction_finish,
|
|
test_construction_teardown,
|
|
test_construction_print_result
|
|
},
|
|
{
|
|
"complex-construction2",
|
|
complex_object_get_type,
|
|
test_construction_setup,
|
|
test_construction_init,
|
|
test_complex_construction_run2,
|
|
test_construction_finish,
|
|
test_construction_teardown,
|
|
test_construction_print_result
|
|
},
|
|
{
|
|
"finalization",
|
|
simple_object_get_type,
|
|
test_construction_setup,
|
|
test_finalization_init,
|
|
test_finalization_run,
|
|
test_finalization_finish,
|
|
test_construction_teardown,
|
|
test_finalization_print_result
|
|
},
|
|
{
|
|
"type-check",
|
|
NULL,
|
|
test_type_check_setup,
|
|
test_type_check_init,
|
|
test_type_check_run,
|
|
test_type_check_finish,
|
|
test_type_check_teardown,
|
|
test_type_check_print_result
|
|
},
|
|
{
|
|
"emit-unhandled",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL),
|
|
test_emission_unhandled_setup,
|
|
test_emission_unhandled_init,
|
|
test_emission_run,
|
|
test_emission_unhandled_finish,
|
|
test_emission_unhandled_teardown,
|
|
test_emission_unhandled_print_result
|
|
},
|
|
{
|
|
"emit-unhandled-empty",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
|
|
test_emission_unhandled_setup,
|
|
test_emission_unhandled_init,
|
|
test_emission_run,
|
|
test_emission_unhandled_finish,
|
|
test_emission_unhandled_teardown,
|
|
test_emission_unhandled_print_result
|
|
},
|
|
{
|
|
"emit-unhandled-generic",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
|
|
test_emission_unhandled_setup,
|
|
test_emission_unhandled_init,
|
|
test_emission_run,
|
|
test_emission_unhandled_finish,
|
|
test_emission_unhandled_teardown,
|
|
test_emission_unhandled_print_result
|
|
},
|
|
{
|
|
"emit-unhandled-generic-empty",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
|
|
test_emission_unhandled_setup,
|
|
test_emission_unhandled_init,
|
|
test_emission_run,
|
|
test_emission_unhandled_finish,
|
|
test_emission_unhandled_teardown,
|
|
test_emission_unhandled_print_result
|
|
},
|
|
{
|
|
"emit-unhandled-args",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
|
|
test_emission_unhandled_setup,
|
|
test_emission_unhandled_init,
|
|
test_emission_run_args,
|
|
test_emission_unhandled_finish,
|
|
test_emission_unhandled_teardown,
|
|
test_emission_unhandled_print_result
|
|
},
|
|
{
|
|
"emit-handled",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL),
|
|
test_emission_handled_setup,
|
|
test_emission_handled_init,
|
|
test_emission_run,
|
|
test_emission_handled_finish,
|
|
test_emission_handled_teardown,
|
|
test_emission_handled_print_result
|
|
},
|
|
{
|
|
"emit-handled-empty",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_EMPTY),
|
|
test_emission_handled_setup,
|
|
test_emission_handled_init,
|
|
test_emission_run,
|
|
test_emission_handled_finish,
|
|
test_emission_handled_teardown,
|
|
test_emission_handled_print_result
|
|
},
|
|
{
|
|
"emit-handled-generic",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC),
|
|
test_emission_handled_setup,
|
|
test_emission_handled_init,
|
|
test_emission_run,
|
|
test_emission_handled_finish,
|
|
test_emission_handled_teardown,
|
|
test_emission_handled_print_result
|
|
},
|
|
{
|
|
"emit-handled-generic-empty",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_GENERIC_EMPTY),
|
|
test_emission_handled_setup,
|
|
test_emission_handled_init,
|
|
test_emission_run,
|
|
test_emission_handled_finish,
|
|
test_emission_handled_teardown,
|
|
test_emission_handled_print_result
|
|
},
|
|
{
|
|
"emit-handled-args",
|
|
GUINT_TO_POINTER (COMPLEX_SIGNAL_ARGS),
|
|
test_emission_handled_setup,
|
|
test_emission_handled_init,
|
|
test_emission_run_args,
|
|
test_emission_handled_finish,
|
|
test_emission_handled_teardown,
|
|
test_emission_handled_print_result
|
|
},
|
|
{
|
|
"notify-unhandled",
|
|
complex_object_get_type,
|
|
test_notify_unhandled_setup,
|
|
test_notify_unhandled_init,
|
|
test_notify_run,
|
|
test_notify_unhandled_finish,
|
|
test_notify_unhandled_teardown,
|
|
test_notify_unhandled_print_result
|
|
},
|
|
{
|
|
"notify-by-pspec-unhandled",
|
|
complex_object_get_type,
|
|
test_notify_unhandled_setup,
|
|
test_notify_unhandled_init,
|
|
test_notify_by_pspec_run,
|
|
test_notify_unhandled_finish,
|
|
test_notify_unhandled_teardown,
|
|
test_notify_unhandled_print_result
|
|
},
|
|
{
|
|
"notify-handled",
|
|
complex_object_get_type,
|
|
test_notify_handled_setup,
|
|
test_notify_handled_init,
|
|
test_notify_run,
|
|
test_notify_handled_finish,
|
|
test_notify_handled_teardown,
|
|
test_notify_handled_print_result
|
|
},
|
|
{
|
|
"notify-by-pspec-handled",
|
|
complex_object_get_type,
|
|
test_notify_handled_setup,
|
|
test_notify_handled_init,
|
|
test_notify_by_pspec_run,
|
|
test_notify_handled_finish,
|
|
test_notify_handled_teardown,
|
|
test_notify_handled_print_result
|
|
},
|
|
{
|
|
"property-set",
|
|
complex_object_get_type,
|
|
test_set_setup,
|
|
test_set_init,
|
|
test_set_run,
|
|
test_set_finish,
|
|
test_set_teardown,
|
|
test_set_print_result
|
|
},
|
|
{
|
|
"property-get",
|
|
complex_object_get_type,
|
|
test_get_setup,
|
|
test_get_init,
|
|
test_get_run,
|
|
test_get_finish,
|
|
test_get_teardown,
|
|
test_get_print_result
|
|
},
|
|
{
|
|
"refcount",
|
|
NULL,
|
|
test_refcount_setup,
|
|
test_refcount_init,
|
|
test_refcount_run,
|
|
test_refcount_finish,
|
|
test_refcount_teardown,
|
|
test_refcount_print_result
|
|
},
|
|
{
|
|
"refcount-1",
|
|
NULL,
|
|
test_refcount_setup,
|
|
test_refcount_init,
|
|
test_refcount_1_run,
|
|
test_refcount_finish,
|
|
test_refcount_teardown,
|
|
test_refcount_print_result
|
|
},
|
|
{
|
|
"refcount-toggle",
|
|
NULL,
|
|
test_refcount_setup,
|
|
test_refcount_init,
|
|
test_refcount_1_run,
|
|
test_refcount_finish,
|
|
test_refcount_teardown,
|
|
test_refcount_print_result
|
|
},
|
|
};
|
|
|
|
static PerformanceTest *
|
|
find_test (const char *name)
|
|
{
|
|
for (size_t i = 0; i < G_N_ELEMENTS (tests); i++)
|
|
{
|
|
if (strcmp (tests[i].name, name) == 0)
|
|
return &tests[i];
|
|
}
|
|
return NULL;
|
|
}
|
|
int
|
|
main (int argc,
|
|
char *argv[])
|
|
{
|
|
PerformanceTest *test;
|
|
GOptionContext *context;
|
|
GError *error = NULL;
|
|
const char *str;
|
|
|
|
if ((str = g_getenv ("GLIB_PERFORMANCE_FACTOR")) && str[0])
|
|
{
|
|
test_factor = g_strtod (str, NULL);
|
|
}
|
|
|
|
context = g_option_context_new ("GObject performance tests");
|
|
g_option_context_add_main_entries (context, cmd_entries, NULL);
|
|
if (!g_option_context_parse (context, &argc, &argv, &error))
|
|
{
|
|
g_printerr ("%s: %s\n", argv[0], error->message);
|
|
return 1;
|
|
}
|
|
|
|
if (test_factor < 0)
|
|
{
|
|
g_printerr ("%s: test factor must be positive\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
global_timer = g_timer_new ();
|
|
|
|
if (argc > 1)
|
|
{
|
|
for (int i = 1; i < argc; i++)
|
|
{
|
|
test = find_test (argv[i]);
|
|
if (test)
|
|
run_test (test);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (size_t k = 0; k < G_N_ELEMENTS (tests); k++)
|
|
run_test (&tests[k]);
|
|
}
|
|
|
|
g_option_context_free (context);
|
|
g_clear_pointer (&global_timer, g_timer_destroy);
|
|
return 0;
|
|
}
|