gobject: cache flags needed for g_type_create_instance()

Every call to g_type_create_instance() currently will incur a RWLock at
least once, but usually twice to test for both G_TYPE_FLAG_ABSTRACT and
G_TYPE_FLAG_DEPRECATED.

Additionally, each call to g_type_instance_free() also checks for these.
That results in a synchronization of GTypeInstance creation across all
threads as well as being a huge amount of overhead when creating instances
like GskRenderNode.

With this patch in place, the next two biggest issues are
g_type_class_ref() and g_type_test_flags() not getting inlined within
gtype.c in release builds. We can address that separately though.

Sysprof shows that the RWLock, with this patch in place, falls off the
profiles.
This commit is contained in:
Christian Hergert 2023-09-26 14:32:45 -07:00 committed by Philip Withnall
parent ec8c62d765
commit 5de7dd5a4b

View File

@ -163,7 +163,9 @@
/* List the flags that are directly accessible via the TypeNode struct flags */ /* List the flags that are directly accessible via the TypeNode struct flags */
#define NODE_FLAG_MASK ( \ #define NODE_FLAG_MASK ( \
G_TYPE_FLAG_ABSTRACT | \
G_TYPE_FLAG_CLASSED | \ G_TYPE_FLAG_CLASSED | \
G_TYPE_FLAG_DEPRECATED | \
G_TYPE_FLAG_INSTANTIATABLE | \ G_TYPE_FLAG_INSTANTIATABLE | \
G_TYPE_FLAG_FINAL) G_TYPE_FLAG_FINAL)
@ -252,7 +254,9 @@ struct _TypeNode
guint n_children; /* writable with lock */ guint n_children; /* writable with lock */
guint n_supers : 8; guint n_supers : 8;
guint n_prerequisites : 9; guint n_prerequisites : 9;
guint is_abstract : 1;
guint is_classed : 1; guint is_classed : 1;
guint is_deprecated : 1;
guint is_instantiatable : 1; guint is_instantiatable : 1;
guint is_final : 1; guint is_final : 1;
guint mutatable_check_cache : 1; /* combines some common path checks */ guint mutatable_check_cache : 1; /* combines some common path checks */
@ -482,7 +486,9 @@ type_node_any_new_W (TypeNode *pnode,
node->supers[0] = type; node->supers[0] = type;
node->supers[1] = 0; node->supers[1] = 0;
node->is_abstract = (type_flags & G_TYPE_FLAG_ABSTRACT) != 0;
node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0; node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
node->is_deprecated = (type_flags & G_TYPE_FLAG_DEPRECATED) != 0;
node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0; node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
if (NODE_IS_IFACE (node)) if (NODE_IS_IFACE (node))
@ -498,9 +504,13 @@ type_node_any_new_W (TypeNode *pnode,
node->supers[0] = type; node->supers[0] = type;
memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1)); memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
node->is_abstract = (type_flags & G_TYPE_FLAG_ABSTRACT) != 0;
node->is_classed = pnode->is_classed; node->is_classed = pnode->is_classed;
node->is_deprecated = (type_flags & G_TYPE_FLAG_DEPRECATED) != 0;
node->is_instantiatable = pnode->is_instantiatable; node->is_instantiatable = pnode->is_instantiatable;
node->is_deprecated |= pnode->is_deprecated;
if (NODE_IS_IFACE (node)) if (NODE_IS_IFACE (node))
{ {
IFACE_NODE_N_PREREQUISITES (node) = 0; IFACE_NODE_N_PREREQUISITES (node) = 0;
@ -573,12 +583,10 @@ type_node_fundamental_new_W (GType ftype,
if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next) if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next)
static_fundamental_next++; static_fundamental_next++;
type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK;
node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags); node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags);
finfo = type_node_fundamental_info_I (node); finfo = type_node_fundamental_info_I (node);
finfo->type_flags = type_flags; finfo->type_flags = type_flags & TYPE_FUNDAMENTAL_FLAG_MASK;
return node; return node;
} }
@ -3919,6 +3927,8 @@ type_add_flags_W (TypeNode *node,
dflags |= flags; dflags |= flags;
type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags)); type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags));
node->is_abstract = (flags & G_TYPE_FLAG_ABSTRACT) != 0;
node->is_deprecated |= (flags & G_TYPE_FLAG_DEPRECATED) != 0;
node->is_final = (flags & G_TYPE_FLAG_FINAL) != 0; node->is_final = (flags & G_TYPE_FLAG_FINAL) != 0;
} }
@ -4007,16 +4017,22 @@ g_type_test_flags (GType type,
{ {
if ((flags & ~NODE_FLAG_MASK) == 0) if ((flags & ~NODE_FLAG_MASK) == 0)
{ {
if (flags & G_TYPE_FLAG_CLASSED) if ((flags & G_TYPE_FLAG_CLASSED) && !node->is_classed)
result |= node->is_classed; return FALSE;
if (flags & G_TYPE_FLAG_INSTANTIATABLE) if ((flags & G_TYPE_FLAG_INSTANTIATABLE) && !node->is_instantiatable)
result |= node->is_instantiatable; return FALSE;
if (flags & G_TYPE_FLAG_FINAL) if ((flags & G_TYPE_FLAG_FINAL) && !node->is_final)
result |= node->is_final; return FALSE;
return result; if ((flags & G_TYPE_FLAG_ABSTRACT) && !node->is_abstract)
return FALSE;
if ((flags & G_TYPE_FLAG_DEPRECATED) && !node->is_deprecated)
return FALSE;
return TRUE;
} }
guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK; guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK;