mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 07:26:15 +01:00
gvarianttype: Garbage Collect GVariantTypeInfo
The goal of this change is to avoid re-parsing `GVariantTypeInfo` on every creation or parsing of a `GVariant` byte-buffer. Parsing presents a non-trivial amount of overhead which can typically be elided. It was discovered that many applications and tooling are re-generating this information upon receiving a D-Bus message as they tend to process messages serially, thus dropping the last reference count. Previously, when the last reference count for a `GVariantTypeInfo` was dropped we would finalize the parsed type information. This change keeps `GVariantTypeInfo` alive in a Garbage Collected array. The array is collected upon reaching a 32 entries. The number 32 was chosen because it is larger than what I've seen active on various D-Bus based applications-or-daemons. Take a simple test case of using `GVariantBuilder` in a loop with a debugoptimized build of GLib. A reduction in wallclock time can be observed in the 35% to more than 70% based on the complexity of the GVariant being created. For cases like ibus-daemon, it was previously parsing `GVariantTypeInfo` up to dozens of times per key-press/release cycle. Closes: #3472
This commit is contained in:
parent
26d8553af5
commit
67532b4555
@ -740,6 +740,36 @@ g_variant_type_info_member_info (GVariantTypeInfo *info,
|
|||||||
/* == new/ref/unref == */
|
/* == new/ref/unref == */
|
||||||
static GRecMutex g_variant_type_info_lock;
|
static GRecMutex g_variant_type_info_lock;
|
||||||
static GHashTable *g_variant_type_info_table;
|
static GHashTable *g_variant_type_info_table;
|
||||||
|
static GPtrArray *g_variant_type_info_gc;
|
||||||
|
|
||||||
|
#define GC_THRESHOLD 32
|
||||||
|
|
||||||
|
static void
|
||||||
|
gc_while_locked (void)
|
||||||
|
{
|
||||||
|
while (g_variant_type_info_gc->len > 0)
|
||||||
|
{
|
||||||
|
GVariantTypeInfo *info = g_ptr_array_steal_index_fast (g_variant_type_info_gc, 0);
|
||||||
|
ContainerInfo *container = (ContainerInfo *)info;
|
||||||
|
|
||||||
|
if (g_atomic_ref_count_dec (&container->ref_count))
|
||||||
|
{
|
||||||
|
TRACE(GLIB_VARIANT_TYPE_INFO_FREE(info));
|
||||||
|
|
||||||
|
g_hash_table_remove (g_variant_type_info_table,
|
||||||
|
container->type_string);
|
||||||
|
|
||||||
|
g_free (container->type_string);
|
||||||
|
|
||||||
|
if (info->container_class == GV_ARRAY_INFO_CLASS)
|
||||||
|
array_info_free (info);
|
||||||
|
else if (info->container_class == GV_TUPLE_INFO_CLASS)
|
||||||
|
tuple_info_free (info);
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* < private >
|
/* < private >
|
||||||
* g_variant_type_info_get:
|
* g_variant_type_info_get:
|
||||||
@ -864,36 +894,33 @@ g_variant_type_info_unref (GVariantTypeInfo *info)
|
|||||||
g_rec_mutex_lock (&g_variant_type_info_lock);
|
g_rec_mutex_lock (&g_variant_type_info_lock);
|
||||||
if (g_atomic_ref_count_dec (&container->ref_count))
|
if (g_atomic_ref_count_dec (&container->ref_count))
|
||||||
{
|
{
|
||||||
|
if (g_variant_type_info_gc == NULL)
|
||||||
|
g_variant_type_info_gc = g_ptr_array_new ();
|
||||||
|
|
||||||
TRACE(GLIB_VARIANT_TYPE_INFO_FREE(info));
|
/* Steal this instance and place it onto the GC queue.
|
||||||
|
* We may bring it back to life before the next GC.
|
||||||
|
*/
|
||||||
|
g_atomic_ref_count_init (&container->ref_count);
|
||||||
|
g_ptr_array_add (g_variant_type_info_gc, info);
|
||||||
|
|
||||||
g_hash_table_remove (g_variant_type_info_table,
|
if (g_variant_type_info_gc->len > GC_THRESHOLD)
|
||||||
container->type_string);
|
gc_while_locked ();
|
||||||
if (g_hash_table_size (g_variant_type_info_table) == 0)
|
|
||||||
{
|
|
||||||
g_hash_table_unref (g_variant_type_info_table);
|
|
||||||
g_variant_type_info_table = NULL;
|
|
||||||
}
|
|
||||||
g_rec_mutex_unlock (&g_variant_type_info_lock);
|
|
||||||
|
|
||||||
g_free (container->type_string);
|
|
||||||
|
|
||||||
if (info->container_class == GV_ARRAY_INFO_CLASS)
|
|
||||||
array_info_free (info);
|
|
||||||
|
|
||||||
else if (info->container_class == GV_TUPLE_INFO_CLASS)
|
|
||||||
tuple_info_free (info);
|
|
||||||
|
|
||||||
else
|
|
||||||
g_assert_not_reached ();
|
|
||||||
}
|
}
|
||||||
else
|
g_rec_mutex_unlock (&g_variant_type_info_lock);
|
||||||
g_rec_mutex_unlock (&g_variant_type_info_lock);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
g_variant_type_info_assert_no_infos (void)
|
g_variant_type_info_assert_no_infos (void)
|
||||||
{
|
{
|
||||||
g_assert (g_variant_type_info_table == NULL);
|
G_GNUC_UNUSED gboolean empty;
|
||||||
|
|
||||||
|
g_rec_mutex_lock (&g_variant_type_info_lock);
|
||||||
|
if (g_variant_type_info_table != NULL)
|
||||||
|
gc_while_locked ();
|
||||||
|
empty = (g_variant_type_info_table == NULL ||
|
||||||
|
g_hash_table_size (g_variant_type_info_table) == 0);
|
||||||
|
g_rec_mutex_unlock (&g_variant_type_info_lock);
|
||||||
|
|
||||||
|
g_assert (empty);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user