From 9a380ee9189266e90de9b643ec1a3ffaca6d96b8 Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Tue, 24 Sep 2024 11:33:07 -0700 Subject: [PATCH] glib/gvariant: Avoid extraneous GBytes ref counting Right now we create a bunch of GBytes which then get their reference count incremented and immediately decremented. This causes quite a bit of disruption for cacheline re-use. Instead, this change creates an internal helper to transfer ownership of GBytes to the new GVariant directly. Surprisingly, this reduced wallclock time by about 6% for a contrived benchmark of building "as" variant with GVariantBuilder. --- glib/gvariant-core.c | 36 ++++++++++++++++++++++++++++-------- glib/gvariant-core.h | 3 +++ glib/gvariant.c | 31 ++++++------------------------- 3 files changed, 37 insertions(+), 33 deletions(-) diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c index eb25d768d..a015adcee 100644 --- a/glib/gvariant-core.c +++ b/glib/gvariant-core.c @@ -593,6 +593,26 @@ GVariant * g_variant_new_from_bytes (const GVariantType *type, GBytes *bytes, gboolean trusted) +{ + return g_variant_new_take_bytes (type, g_bytes_ref (bytes), trusted); +} + +/* -- internal -- */ + +/* < internal > + * g_variant_new_take_bytes: + * @bytes: (transfer full): a #GBytes + * @trusted: if the contents of @bytes are trusted + * + * The same as g_variant_new_from_bytes() but takes ownership + * of @bytes. + * + * Returns: a new #GVariant with a floating reference + */ +GVariant * +g_variant_new_take_bytes (const GVariantType *type, + GBytes *bytes, + gboolean trusted) { GVariant *value; guint alignment; @@ -639,21 +659,23 @@ g_variant_new_from_bytes (const GVariantType *type, if (aligned_size != 0) memcpy (aligned_data, g_bytes_get_data (bytes, NULL), aligned_size); - bytes = owned_bytes = g_bytes_new_with_free_func (aligned_data, - aligned_size, - free, aligned_data); + owned_bytes = bytes; + bytes = g_bytes_new_with_free_func (aligned_data, + aligned_size, + free, aligned_data); aligned_data = NULL; #else /* NOTE: there may be platforms that lack posix_memalign() and also * have malloc() that returns non-8-aligned. if so, we need to try * harder here. */ - bytes = owned_bytes = g_bytes_new (g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes)); + owned_bytes = bytes; + bytes = g_bytes_new (g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes)); #endif } - value->contents.serialised.bytes = g_bytes_ref (bytes); + value->contents.serialised.bytes = bytes; if (size && g_bytes_get_size (bytes) != size) { @@ -682,8 +704,6 @@ g_variant_new_from_bytes (const GVariantType *type, return value; } -/* -- internal -- */ - /* < internal > * g_variant_new_from_children: * @type: a #GVariantType diff --git a/glib/gvariant-core.h b/glib/gvariant-core.h index fb5f4bff4..44388d83f 100644 --- a/glib/gvariant-core.h +++ b/glib/gvariant-core.h @@ -27,6 +27,9 @@ /* gvariant-core.c */ +GVariant * g_variant_new_take_bytes (const GVariantType *type, + GBytes *bytes, + gboolean trusted); GVariant * g_variant_new_from_children (const GVariantType *type, GVariant **children, gsize n_children, diff --git a/glib/gvariant.c b/glib/gvariant.c index 4080ebf1c..e6a73698d 100644 --- a/glib/gvariant.c +++ b/glib/gvariant.c @@ -321,14 +321,7 @@ g_variant_new_from_trusted (const GVariantType *type, gconstpointer data, gsize size) { - GVariant *value; - GBytes *bytes; - - bytes = g_bytes_new (data, size); - value = g_variant_new_from_bytes (type, bytes, TRUE); - g_bytes_unref (bytes); - - return value; + return g_variant_new_take_bytes (type, g_bytes_new (data, size), TRUE); } /** @@ -1311,14 +1304,8 @@ g_variant_new_take_string (gchar *string) if G_LIKELY (g_utf8_validate (string, -1, &end)) { - GVariant *value; - GBytes *bytes; - - bytes = g_bytes_new_take (string, end - string + 1); - value = g_variant_new_from_bytes (G_VARIANT_TYPE_STRING, bytes, TRUE); - g_bytes_unref (bytes); - - return value; + GBytes *bytes = g_bytes_new_take (string, end - string + 1); + return g_variant_new_take_bytes (G_VARIANT_TYPE_STRING, g_steal_pointer (&bytes), TRUE); } g_critical ("g_variant_new_take_string(): requires valid UTF-8"); @@ -1358,8 +1345,7 @@ g_variant_new_printf (const gchar *format_string, va_end (ap); bytes = g_bytes_new_take (string, strlen (string) + 1); - value = g_variant_new_from_bytes (G_VARIANT_TYPE_STRING, bytes, TRUE); - g_bytes_unref (bytes); + value = g_variant_new_take_bytes (G_VARIANT_TYPE_STRING, g_steal_pointer (&bytes), TRUE); return value; } @@ -6167,8 +6153,7 @@ g_variant_byteswap (GVariant *value) g_variant_serialised_byteswap (serialised); bytes = g_bytes_new_take (serialised.data, serialised.size); - new = g_variant_ref_sink (g_variant_new_from_bytes (g_variant_get_type (value), bytes, TRUE)); - g_bytes_unref (bytes); + new = g_variant_ref_sink (g_variant_new_take_bytes (g_variant_get_type (value), g_steal_pointer (&bytes), TRUE)); } else if (alignment) /* (potentially) contains multi-byte numeric data */ @@ -6233,7 +6218,6 @@ g_variant_new_from_data (const GVariantType *type, GDestroyNotify notify, gpointer user_data) { - GVariant *value; GBytes *bytes; g_return_val_if_fail (g_variant_type_is_definite (type), NULL); @@ -6244,10 +6228,7 @@ g_variant_new_from_data (const GVariantType *type, else bytes = g_bytes_new_static (data, size); - value = g_variant_new_from_bytes (type, bytes, trusted); - g_bytes_unref (bytes); - - return value; + return g_variant_new_take_bytes (type, g_steal_pointer (&bytes), trusted); } /* Epilogue {{{1 */