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.
This commit is contained in:
Christian Hergert 2024-09-24 11:33:07 -07:00 committed by Philip Withnall
parent 842c828535
commit 9a380ee918
3 changed files with 37 additions and 33 deletions

View File

@ -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

View File

@ -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,

View File

@ -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 */