gobject: Register a global with the object/interface GType

This makes the G_DEFINE_TYPE(), G_DEFINE_INTERFACE() and similar variants
provide a TypeName##_type_id global simimlar to how the private offset is
stored as a global.

What this allows for, is for applications and libraries which have high
demand on the type system to have an escape hatch to improve performance.

It has been observed that most of the type checking comes from inside the
same module that implements the type. Therefore, if that source file can
access the GType without an external call to the get_type() function, the
overhead can be reduced to an address load.

For example, this is used in libdex heavily to ensure that get_type() do
not show up in performance profiles. This is done by redefining the type
macro to use the global variable.

  #undef FOO_TYPE_BAR
  #define FOO_TYPE_BAR FooBar_type_id

The one place where you need to be careful of this is the new function
which may cause the registration of the type if global registration at
library/application startup is not performed.

Additionally, if using new-style G_DECLARE_* macros, you may also want to
override the IS_TYPE() macro to use the fast path.

  #define FOO_IS_BAR(obj) G_TYPE_CHECK_INSTANCE_TYPE(obj, FOO_TYPE_BAR)

On this system, this can have a wild performance implication. For example,
the type check for GDBusMessage when dragging a window around in GNOME
Shell and activating the overview had a whopping 2.96% of samples.
This commit is contained in:
Christian Hergert 2024-09-06 09:54:10 -07:00
parent 8810cf7a24
commit afa562c832

View File

@ -2285,6 +2285,7 @@ static void type_name##_class_init (TypeName##Class *klass); \
static GType type_name##_get_type_once (void); \
static gpointer type_name##_parent_class = NULL; \
static gint TypeName##_private_offset; \
static GType TypeName##_type_id; \
\
_G_DEFINE_TYPE_EXTENDED_CLASS_INIT(TypeName, type_name) \
\
@ -2306,6 +2307,7 @@ type_name##_get_type (void) \
if (_g_type_once_init_enter (&static_g_define_type_id)) \
{ \
GType g_define_type_id = type_name##_get_type_once (); \
TypeName##_type_id = g_define_type_id; \
_g_type_once_init_leave (&static_g_define_type_id, g_define_type_id); \
} \
return static_g_define_type_id; \
@ -2342,6 +2344,7 @@ type_name##_get_type_once (void) \
#define _G_DEFINE_INTERFACE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PREREQ) \
\
static void type_name##_default_init (TypeName##Interface *klass); \
static GType TypeName##_type_id; \
\
GType \
type_name##_get_type (void) \
@ -2357,6 +2360,7 @@ type_name##_get_type (void) \
0, \
(GInstanceInitFunc)NULL, \
(GTypeFlags) 0); \
TypeName##_type_id = g_define_type_id; \
if (TYPE_PREREQ != G_TYPE_INVALID) \
g_type_interface_add_prerequisite (g_define_type_id, TYPE_PREREQ); \
{ /* custom code follows */