mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-12 15:36:17 +01:00
glib/gbytes: save small byte buffers inline
When dealing with small allocations it can save considerable cycles to do a single allocation for both the GBytes and the data by tacking it onto the end of the GBytes. Care is taken to preserve the glibc expectation of 2*sizeof(void*) alignment of allocations at the expense of some padding bytes. The degenerate case here is when you want to steal the bytes afterwards but that amounts to the same overhead as the status-quo. Where this can help considerably is in GVariant building such as g_variant_new_int32() which allocates for the GVariant, the GBytes, and the int32 within the GBytes. In a simple benchmark of using GVariantBuilder to create "(ii)" variants this saved about 10% in wallclock time.
This commit is contained in:
parent
84b6f747cb
commit
1e3b010af8
@ -28,7 +28,6 @@
|
|||||||
#include <glib/garray.h>
|
#include <glib/garray.h>
|
||||||
#include <glib/gstrfuncs.h>
|
#include <glib/gstrfuncs.h>
|
||||||
#include <glib/gatomic.h>
|
#include <glib/gatomic.h>
|
||||||
#include <glib/gslice.h>
|
|
||||||
#include <glib/gtestutils.h>
|
#include <glib/gtestutils.h>
|
||||||
#include <glib/gmem.h>
|
#include <glib/gmem.h>
|
||||||
#include <glib/gmessages.h>
|
#include <glib/gmessages.h>
|
||||||
@ -36,6 +35,12 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#if GLIB_SIZEOF_VOID_P == 8
|
||||||
|
# define G_BYTES_MAX_INLINE (128 - sizeof(GBytesInline))
|
||||||
|
#else
|
||||||
|
# define G_BYTES_MAX_INLINE (64 - sizeof(GBytesInline))
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GBytes: (copy-func g_bytes_ref) (free-func g_bytes_unref)
|
* GBytes: (copy-func g_bytes_ref) (free-func g_bytes_unref)
|
||||||
*
|
*
|
||||||
@ -77,6 +82,21 @@ struct _GBytes
|
|||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GBytes bytes;
|
||||||
|
/* Despite no guarantee about alignment in GBytes, it is nice to
|
||||||
|
* provide that to ensure that any code which predates support
|
||||||
|
* for inline data continues to work without disruption. malloc()
|
||||||
|
* on glibc systems would guarantee 2*sizeof(void*) aligned
|
||||||
|
* allocations and this matches that.
|
||||||
|
*/
|
||||||
|
gsize padding;
|
||||||
|
guint8 inline_data[];
|
||||||
|
} GBytesInline;
|
||||||
|
|
||||||
|
G_STATIC_ASSERT (G_STRUCT_OFFSET (GBytesInline, inline_data) == (6 * GLIB_SIZEOF_VOID_P));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_bytes_new:
|
* g_bytes_new:
|
||||||
* @data: (transfer none) (array length=size) (element-type guint8) (nullable):
|
* @data: (transfer none) (array length=size) (element-type guint8) (nullable):
|
||||||
@ -87,6 +107,9 @@ struct _GBytes
|
|||||||
*
|
*
|
||||||
* @data is copied. If @size is 0, @data may be %NULL.
|
* @data is copied. If @size is 0, @data may be %NULL.
|
||||||
*
|
*
|
||||||
|
* As an optimization, g_bytes_new() may avoid an extra allocation by copying
|
||||||
|
* the data within the resulting bytes structure if sufficiently small (since GLib 2.84).
|
||||||
|
*
|
||||||
* Returns: (transfer full): a new #GBytes
|
* Returns: (transfer full): a new #GBytes
|
||||||
*
|
*
|
||||||
* Since: 2.32
|
* Since: 2.32
|
||||||
@ -97,6 +120,22 @@ g_bytes_new (gconstpointer data,
|
|||||||
{
|
{
|
||||||
g_return_val_if_fail (data != NULL || size == 0, NULL);
|
g_return_val_if_fail (data != NULL || size == 0, NULL);
|
||||||
|
|
||||||
|
if (size <= G_BYTES_MAX_INLINE)
|
||||||
|
{
|
||||||
|
GBytesInline *bytes;
|
||||||
|
|
||||||
|
bytes = g_malloc (sizeof *bytes + size);
|
||||||
|
bytes->bytes.data = bytes->inline_data;
|
||||||
|
bytes->bytes.size = size;
|
||||||
|
bytes->bytes.free_func = NULL;
|
||||||
|
bytes->bytes.user_data = NULL;
|
||||||
|
g_atomic_ref_count_init (&bytes->bytes.ref_count);
|
||||||
|
|
||||||
|
memcpy (bytes->inline_data, data, size);
|
||||||
|
|
||||||
|
return (GBytes *)bytes;
|
||||||
|
}
|
||||||
|
|
||||||
return g_bytes_new_take (g_memdup2 (data, size), size);
|
return g_bytes_new_take (g_memdup2 (data, size), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +222,7 @@ g_bytes_new_with_free_func (gconstpointer data,
|
|||||||
|
|
||||||
g_return_val_if_fail (data != NULL || size == 0, NULL);
|
g_return_val_if_fail (data != NULL || size == 0, NULL);
|
||||||
|
|
||||||
bytes = g_slice_new (GBytes);
|
bytes = g_new (GBytes, 1);
|
||||||
bytes->data = data;
|
bytes->data = data;
|
||||||
bytes->size = size;
|
bytes->size = size;
|
||||||
bytes->free_func = free_func;
|
bytes->free_func = free_func;
|
||||||
@ -335,7 +374,7 @@ g_bytes_unref (GBytes *bytes)
|
|||||||
{
|
{
|
||||||
if (bytes->free_func != NULL)
|
if (bytes->free_func != NULL)
|
||||||
bytes->free_func (bytes->user_data);
|
bytes->free_func (bytes->user_data);
|
||||||
g_slice_free (GBytes, bytes);
|
g_free (bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,7 +490,7 @@ try_steal_and_unref (GBytes *bytes,
|
|||||||
{
|
{
|
||||||
*size = bytes->size;
|
*size = bytes->size;
|
||||||
result = (gpointer)bytes->data;
|
result = (gpointer)bytes->data;
|
||||||
g_slice_free (GBytes, bytes);
|
g_free (bytes);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,8 +508,9 @@ try_steal_and_unref (GBytes *bytes,
|
|||||||
*
|
*
|
||||||
* As an optimization, the byte data is returned without copying if this was
|
* As an optimization, the byte data is returned without copying if this was
|
||||||
* the last reference to bytes and bytes was created with g_bytes_new(),
|
* the last reference to bytes and bytes was created with g_bytes_new(),
|
||||||
* g_bytes_new_take() or g_byte_array_free_to_bytes(). In all other cases the
|
* g_bytes_new_take() or g_byte_array_free_to_bytes() and the buffer was larger
|
||||||
* data is copied.
|
* than the size #GBytes may internalize within its allocation. In all other
|
||||||
|
* cases the data is copied.
|
||||||
*
|
*
|
||||||
* Returns: (transfer full) (array length=size) (element-type guint8)
|
* Returns: (transfer full) (array length=size) (element-type guint8)
|
||||||
* (not nullable): a pointer to the same byte data, which should be
|
* (not nullable): a pointer to the same byte data, which should be
|
||||||
@ -516,8 +556,9 @@ g_bytes_unref_to_data (GBytes *bytes,
|
|||||||
*
|
*
|
||||||
* As an optimization, the byte data is transferred to the array without copying
|
* As an optimization, the byte data is transferred to the array without copying
|
||||||
* if this was the last reference to bytes and bytes was created with
|
* if this was the last reference to bytes and bytes was created with
|
||||||
* g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes(). In all
|
* g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes() and the
|
||||||
* other cases the data is copied.
|
* buffer was larger than the size #GBytes may internalize within its allocation.
|
||||||
|
* In all other cases the data is copied.
|
||||||
*
|
*
|
||||||
* Do not use it if @bytes contains more than %G_MAXUINT
|
* Do not use it if @bytes contains more than %G_MAXUINT
|
||||||
* bytes. #GByteArray stores the length of its data in #guint, which
|
* bytes. #GByteArray stores the length of its data in #guint, which
|
||||||
|
@ -28,8 +28,22 @@ struct _GBytes
|
|||||||
gpointer user_data;
|
gpointer user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const gchar *NYAN = "nyannyan";
|
static const gchar NYAN[128] = {
|
||||||
static const gsize N_NYAN = 8;
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||||
|
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||||
|
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
|
||||||
|
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||||
|
51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
|
||||||
|
61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
|
||||||
|
71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
|
||||||
|
81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
|
||||||
|
91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
|
||||||
|
101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
||||||
|
111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
|
||||||
|
121, 122, 123, 124, 125, 126, 127
|
||||||
|
};
|
||||||
|
#define N_NYAN sizeof(NYAN)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_new (void)
|
test_new (void)
|
||||||
|
Loading…
Reference in New Issue
Block a user