[glib/gobject-speedups4: 19/19] gobject: Speed up property lookup
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/gobject-speedups4: 19/19] gobject: Speed up property lookup
- Date: Tue, 7 Jun 2022 12:27:44 +0000 (UTC)
commit 713fb450d9a9619f683f4ac43347f720309fd886
Author: Matthias Clasen <mclasen redhat com>
Date: Fri May 20 20:49:05 2022 -0400
gobject: Speed up property lookup
When the param specs are provided as an array
with g_object_class_install_properties, keep
a copy of that array around and use it for
looking up properties without the param spec
pool.
Note that this is an opportunistic optimization -
currently, it only works for properties of the
class itself, not for parent classes, and it
only works if the property names are identical
string literals (we're at the mercy of the linker
for that).
If we don't get lucky, we fall back to using
the pspec pool as usual.
gobject/gobject.c | 152 +++++++++++++++++++++++++++++++++++++-----------------
gobject/gobject.h | 6 ++-
2 files changed, 111 insertions(+), 47 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 6db045f15b..81d06eba40 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -485,6 +485,8 @@ g_object_base_class_init (GObjectClass *class)
class->n_construct_properties = g_slist_length (class->construct_properties);
class->get_property = NULL;
class->set_property = NULL;
+ class->pspecs = NULL;
+ class->n_pspecs = 0;
}
static void
@@ -704,6 +706,61 @@ g_object_class_install_property (GObjectClass *class,
pspec);
}
+typedef struct {
+ const char *name;
+ GParamSpec *pspec;
+} PspecEntry;
+
+static int
+compare_pspec_entry (const void *a,
+ const void *b)
+{
+ const PspecEntry *ae = a;
+ const PspecEntry *be = b;
+
+ return ae->name < be->name ? -1 : (ae->name > be->name ? 1 : 0);
+}
+
+static inline GParamSpec *
+find_pspec (GObjectClass *class,
+ const char *property_name)
+{
+ PspecEntry *pspecs = (PspecEntry *)class->pspecs;
+ guint n_pspecs = class->n_pspecs;
+
+ if (n_pspecs < 10)
+ {
+ for (guint i = 0; i < n_pspecs; i++)
+ {
+ if (pspecs[i].name == property_name)
+ return pspecs[i].pspec;
+ }
+ }
+ else
+ {
+ int lower = 0;
+ int upper = (int)class->n_pspecs - 1;
+ int mid;
+
+ while (lower <= upper)
+ {
+ mid = (lower + upper) / 2;
+
+ if (property_name < pspecs[mid].name)
+ upper = mid - 1;
+ else if (property_name > pspecs[mid].name)
+ lower = mid + 1;
+ else
+ return pspecs[mid].pspec;
+ }
+ }
+
+ return g_param_spec_pool_lookup (pspec_pool,
+ property_name,
+ ((GTypeClass *)class)->g_type,
+ TRUE);
+}
+
/**
* g_object_class_install_properties:
* @oclass: a #GObjectClass
@@ -810,6 +867,21 @@ g_object_class_install_properties (GObjectClass *oclass,
break;
}
}
+
+ if (oclass->pspecs == NULL)
+ {
+ PspecEntry *entries = g_new (PspecEntry, n_pspecs - 1);
+ for (i = 1; i < n_pspecs; i++)
+ {
+ entries[i - 1].name = pspecs[i]->name;
+ entries[i - 1].pspec = pspecs[i];
+ }
+
+ qsort (entries, n_pspecs - 1, sizeof (PspecEntry), compare_pspec_entry);
+
+ oclass->pspecs = entries;
+ oclass->n_pspecs = n_pspecs - 1;
+ }
}
/**
@@ -872,25 +944,16 @@ g_object_class_find_property (GObjectClass *class,
const gchar *property_name)
{
GParamSpec *pspec;
- GParamSpec *redirect;
-
+
g_return_val_if_fail (G_IS_OBJECT_CLASS (class), NULL);
g_return_val_if_fail (property_name != NULL, NULL);
-
- pspec = g_param_spec_pool_lookup (pspec_pool,
- property_name,
- G_OBJECT_CLASS_TYPE (class),
- TRUE);
- if (pspec)
- {
- redirect = g_param_spec_get_redirect_target (pspec);
- if (redirect)
- return redirect;
- else
- return pspec;
- }
- else
- return NULL;
+
+ pspec = find_pspec (class, property_name);
+
+ if (pspec && ((GTypeInstance *)pspec)->g_class->g_type == G_TYPE_PARAM_OVERRIDE)
+ pspec = ((GParamSpecOverride *)pspec)->overridden;
+
+ return pspec;
}
/**
@@ -2217,8 +2280,8 @@ g_object_new_with_properties (GType object_type,
params = g_newa (GObjectConstructParam, n_properties);
for (i = 0; i < n_properties; i++)
{
- GParamSpec *pspec;
- pspec = g_param_spec_pool_lookup (pspec_pool, names[i], object_type, TRUE);
+ GParamSpec *pspec = find_pspec (class, names[i]);
+
if (!g_object_new_is_valid_property (object_type, pspec, names[i], params, count))
continue;
params[count].pspec = pspec;
@@ -2283,9 +2346,8 @@ g_object_newv (GType object_type,
for (i = 0; i < n_parameters; i++)
{
- GParamSpec *pspec;
+ GParamSpec *pspec = find_pspec (class, parameters[i].name);
- pspec = g_param_spec_pool_lookup (pspec_pool, parameters[i].name, object_type, TRUE);
if (!g_object_new_is_valid_property (object_type, pspec, parameters[i].name, cparams, j))
continue;
@@ -2356,9 +2418,7 @@ g_object_new_valist (GType object_type,
do
{
gchar *error = NULL;
- GParamSpec *pspec;
-
- pspec = g_param_spec_pool_lookup (pspec_pool, name, object_type, TRUE);
+ GParamSpec *pspec = find_pspec (class, name);
if (!g_object_new_is_valid_property (object_type, pspec, name, params, n_params))
break;
@@ -2524,7 +2584,7 @@ g_object_setv (GObject *object,
guint i;
GObjectNotifyQueue *nqueue = NULL;
GParamSpec *pspec;
- GType obj_type;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
@@ -2532,14 +2592,15 @@ g_object_setv (GObject *object,
return;
g_object_ref (object);
- obj_type = G_OBJECT_TYPE (object);
+
+ class = G_OBJECT_GET_CLASS (object);
if (_g_object_has_notify_handler (object))
nqueue = g_object_notify_queue_freeze (object, FALSE);
for (i = 0; i < n_properties; i++)
{
- pspec = g_param_spec_pool_lookup (pspec_pool, names[i], obj_type, TRUE);
+ pspec = find_pspec (class, names[i]);
if (!g_object_set_is_valid_property (object, pspec, names[i]))
break;
@@ -2569,6 +2630,7 @@ g_object_set_valist (GObject *object,
{
GObjectNotifyQueue *nqueue = NULL;
const gchar *name;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
@@ -2576,7 +2638,9 @@ g_object_set_valist (GObject *object,
if (_g_object_has_notify_handler (object))
nqueue = g_object_notify_queue_freeze (object, FALSE);
-
+
+ class = G_OBJECT_GET_CLASS (object);
+
name = first_property_name;
while (name)
{
@@ -2585,10 +2649,7 @@ g_object_set_valist (GObject *object,
gchar *error = NULL;
GTypeValueTable *vtab;
- pspec = g_param_spec_pool_lookup (pspec_pool,
- name,
- G_OBJECT_TYPE (object),
- TRUE);
+ pspec = find_pspec (class, name);
if (!g_object_set_is_valid_property (object, pspec, name))
break;
@@ -2661,7 +2722,7 @@ g_object_getv (GObject *object,
{
guint i;
GParamSpec *pspec;
- GType obj_type;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
@@ -2670,12 +2731,14 @@ g_object_getv (GObject *object,
g_object_ref (object);
+ class = G_OBJECT_GET_CLASS (object);
+
memset (values, 0, n_properties * sizeof (GValue));
- obj_type = G_OBJECT_TYPE (object);
for (i = 0; i < n_properties; i++)
{
- pspec = g_param_spec_pool_lookup (pspec_pool, names[i], obj_type, TRUE);
+ pspec = find_pspec (class, names[i]);
+
if (!g_object_get_is_valid_property (object, pspec, names[i]))
break;
g_value_init (&values[i], pspec->value_type);
@@ -2705,23 +2768,23 @@ g_object_get_valist (GObject *object,
va_list var_args)
{
const gchar *name;
+ GObjectClass *class;
g_return_if_fail (G_IS_OBJECT (object));
g_object_ref (object);
-
+
+ class = G_OBJECT_GET_CLASS (object);
+
name = first_property_name;
-
+
while (name)
{
GValue value = G_VALUE_INIT;
GParamSpec *pspec;
gchar *error;
-
- pspec = g_param_spec_pool_lookup (pspec_pool,
- name,
- G_OBJECT_TYPE (object),
- TRUE);
+
+ pspec = find_pspec (class, name);
if (!g_object_get_is_valid_property (object, pspec, name))
break;
@@ -2881,10 +2944,7 @@ g_object_get_property (GObject *object,
g_object_ref (object);
- pspec = g_param_spec_pool_lookup (pspec_pool,
- property_name,
- G_OBJECT_TYPE (object),
- TRUE);
+ pspec = find_pspec (G_OBJECT_GET_CLASS (object), property_name);
if (g_object_get_is_valid_property (object, pspec, property_name))
{
diff --git a/gobject/gobject.h b/gobject/gobject.h
index c67794ae50..93502b01d6 100644
--- a/gobject/gobject.h
+++ b/gobject/gobject.h
@@ -370,8 +370,12 @@ struct _GObjectClass
gsize flags;
gsize n_construct_properties;
+
+ gpointer pspecs;
+ guint n_pspecs;
+
/* padding */
- gpointer pdummy[5];
+ gpointer pdummy[3];
};
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]