+Mon Dec 5 15:53:20 2005 Tim Janik <timj@imendio.com>
+
+ * glib/gslice.c: implement chain walking for arbitrary ->next pointer
+ offsets in g_slice_free_chain_with_offset() based on a patch by behdad
+ in bug 323178. moved time consuming logic from g_slice_free() out of
+ the inner loop, so g_slice_free_chain_with_offset() provides a real
+ performance benefit over g_slice_free1() now.
+
+ * glib/gslice.h: renamed g_slice_free_chain() to
+ g_slice_free_chain_with_offset(). implemented g_slice_free_chain() as
+ a type-safe macro as suggested in bug 323178.
+ simplified the macro implementation of g_slice_free() and implemented
+ it in a type safe manner for all compliers as suggested by Morten
+ Welinder <mortenw@gnome.org>.
+
+ * glib/gmain.c:
+ * glib/glist.c:
+ * glib/gslist.c:
+ * glib/glib.symbols: s/g_slice_free_chain/g_slice_free_chain_with_offset/
+
2005-12-05 Matthias Clasen <mclasen@redhat.com>
* glib/gasyncqueue.c: Add some docs.
+Mon Dec 5 15:53:20 2005 Tim Janik <timj@imendio.com>
+
+ * glib/gslice.c: implement chain walking for arbitrary ->next pointer
+ offsets in g_slice_free_chain_with_offset() based on a patch by behdad
+ in bug 323178. moved time consuming logic from g_slice_free() out of
+ the inner loop, so g_slice_free_chain_with_offset() provides a real
+ performance benefit over g_slice_free1() now.
+
+ * glib/gslice.h: renamed g_slice_free_chain() to
+ g_slice_free_chain_with_offset(). implemented g_slice_free_chain() as
+ a type-safe macro as suggested in bug 323178.
+ simplified the macro implementation of g_slice_free() and implemented
+ it in a type safe manner for all compliers as suggested by Morten
+ Welinder <mortenw@gnome.org>.
+
+ * glib/gmain.c:
+ * glib/glist.c:
+ * glib/gslist.c:
+ * glib/glib.symbols: s/g_slice_free_chain/g_slice_free_chain_with_offset/
+
2005-12-05 Matthias Clasen <mclasen@redhat.com>
* glib/gasyncqueue.c: Add some docs.
+Mon Dec 5 15:53:20 2005 Tim Janik <timj@imendio.com>
+
+ * glib/gslice.c: implement chain walking for arbitrary ->next pointer
+ offsets in g_slice_free_chain_with_offset() based on a patch by behdad
+ in bug 323178. moved time consuming logic from g_slice_free() out of
+ the inner loop, so g_slice_free_chain_with_offset() provides a real
+ performance benefit over g_slice_free1() now.
+
+ * glib/gslice.h: renamed g_slice_free_chain() to
+ g_slice_free_chain_with_offset(). implemented g_slice_free_chain() as
+ a type-safe macro as suggested in bug 323178.
+ simplified the macro implementation of g_slice_free() and implemented
+ it in a type safe manner for all compliers as suggested by Morten
+ Welinder <mortenw@gnome.org>.
+
+ * glib/gmain.c:
+ * glib/glist.c:
+ * glib/gslist.c:
+ * glib/glib.symbols: s/g_slice_free_chain/g_slice_free_chain_with_offset/
+
2005-12-05 Matthias Clasen <mclasen@redhat.com>
* glib/gasyncqueue.c: Add some docs.
+Mon Dec 5 15:53:37 2005 Tim Janik <timj@imendio.com>
+
+ * glib/tmpl/memory_slices.sgml: updates to new g_slice API
+ and minor fixes.
+
2005-12-05 Matthias Clasen <mclasen@redhat.com>
* gobject/tmpl/generic_values.sgml:
<!-- ##### SECTION Long_Description ##### -->
<para>
-Memory slices provide a space-efficient way to allocate equal-sized
-pieces of memory, just like #GMemChunks, while avoiding their scalability
-and performance problems.
+Memory slices provide a space-efficient and multi processing scalable
+way to allocate equal-sized pieces of memory, just like the original
+#GMemChunks (from GLib <= 2.8), while avoiding their excessive
+memroy-waste scalability and performance problems.
</para>
<para>
To achieve these goals, the slice allocator uses a sophisticated,
layered design that has been inspired by Bonwick's slab allocator
-<footnote><para><ulink url="http://citeseer.ist.psu.edu/bonwick94slab.html">[Bonwick94]</ulink> Jeff Bonwick, The slab allocator: An object-caching kernel
+<footnote><para>
+<ulink url="http://citeseer.ist.psu.edu/bonwick94slab.html">[Bonwick94]</ulink> Jeff Bonwick, The slab allocator: An object-caching kernel
memory allocator. USENIX 1994, and
- <ulink url="http://citeseer.ist.psu.edu/bonwick01magazines.html">[Bonwick01]</ulink> Bonwick and Jonathan Adams, Magazines and vmem: Extending the
-slab allocator to many cpu's and arbitrary resources. USENIX 2001</para></footnote>.
+<ulink url="http://citeseer.ist.psu.edu/bonwick01magazines.html">[Bonwick01]</ulink> Bonwick and Jonathan Adams, Magazines and vmem: Extending the
+slab allocator to many cpu's and arbitrary resources. USENIX 2001
+</para></footnote>.
It uses posix_memalign() to optimize allocations of many equally
sized chunks, and has per-thread free lists (the so-called magazine layer)
to quickly satisfy allocation requests of already known structure sizes.
<!-- ##### FUNCTION g_slice_alloc ##### -->
<para>
Allocates a block of memory from the slice allocator.
+The block adress handed out is guaranteed to be aligned
+to at leats 2 * sizeof (void*).
</para>
@block_size: the number of bytes to allocate
-@Returns: a pointer to the allocated
+@Returns: a pointer to the allocated memory block
@Since: 2.10
<!-- ##### FUNCTION g_slice_alloc0 ##### -->
<para>
-Allocates a block of memory from the slice allocator, setting the
-memory to 0.
+Allocates a block of memory via g_slice_alloc()
+and initialize the returned memory to 0.
</para>
@block_size: the number of bytes to allocate
<!-- ##### FUNCTION g_slice_free1 ##### -->
<para>
-Frees a block of memory. The memory must have been allocated from
-the slice allocator.
+Frees a block of memory. The memory must have been allocated via
+g_slice_alloc() or g_slice_alloc0()
+and the @block_size has to match the size specified upon allocation.
</para>
@block_size: the size of the block
@mem_block: a pointer to the block to free
@Since: 2.10
-<!-- ##### FUNCTION g_slice_free_chain ##### -->
+<!-- ##### FUNCTION g_slice_free_chain_with_offset ##### -->
<para>
-Frees a linked list of memory block. The memory blocks must be equal-sized,
-allocated from the slice allocator and linked together by a
-<literal>next</literal> pointer stored in the @next_offset's word of
-each block.
+Frees a linked list of memory blocks. The memory blocks must be equal-sized,
+allocated via
+g_slice_alloc() or g_slice_alloc0()
+and linked together by a <literal>next</literal> pointer (similar to #GSList)
+stored in the word of each block denoted by @next_offset.
+The @block_size has to match the size specified upon allocation.
</para>
-<para>
-Currently, this function only supports blocks which store their
-<literal>next</literal> pointer in the same position as #GSList.
-Therefore, @next_offset must be 1.
-</para>
-
@block_size: the size of the blocks
@mem_chain: a pointer to the first block
@next_offset: the offset of the <literal>next</literal> pointer
@Since: 2.10
+<!-- ##### MACRO g_slice_free_chain ##### -->
+<para>
+Frees a linked list of memory blocks of structure type @type.
+The memory blocks must be equal-sized, allocated via
+g_slice_alloc() or g_slice_alloc0()
+and linked together by a @next pointer (similar to #GSList). The name of the
+@next field in @type is passed as third argument.
+</para>
+@type: the type of the @mem_chain blocks
+@mem_chain: a pointer to the first block of the chain
+@next: the field name of the next pointer in @type
+@Since: 2.10
+
<!-- ##### MACRO g_slice_new ##### -->
<para>
A convenience macro to allocate a block of memory from the slice allocator.
-It calls g_slice_alloc() and casts the returned pointer to a pointer to
-the given type, avoiding a type cast in the source code.
+It calls g_slice_alloc() with sizeof (@type) and casts the returned pointer
+to a pointer of the given type, avoiding a type cast in the source code.
</para>
@type: the type to allocate, typically a structure name
<!-- ##### MACRO g_slice_new0 ##### -->
<para>
A convenience macro to allocate a block of memory from the slice allocator
-and set the memory to 0. It calls g_slice_alloc0() and casts the returned
-pointer to a pointer to the given type, avoiding a type cast in the source
-code.
+and set the memory to 0. It calls g_slice_alloc0() with sizeof (@type) and
+casts the returned pointer to a pointer of the given type, avoiding a type
+cast in the source code.
</para>
@type: the type to allocate, typically a structure name
g_slice_alloc G_GNUC_MALLOC
g_slice_alloc0 G_GNUC_MALLOC
g_slice_free1
-g_slice_free_chain
+g_slice_free_chain_with_offset
g_slice_set_config
g_slice_get_config
g_slice_get_config_state
void
g_list_free (GList *list)
{
- g_slice_free_chain (sizeof (GList), list, G_STRUCT_OFFSET (GList, next));
+ g_slice_free_chain (GList, list, next);
}
void
struct _GPollRec
{
GPollFD *fd;
- GPollRec *next; /* chaining via second pointer member allows use of g_slice_free_chain() */
+ GPollRec *next;
gint priority;
};
poll_rec_list_free (GMainContext *context,
GPollRec *list)
{
- g_slice_free_chain (sizeof (GPollRec), list, G_STRUCT_OFFSET (GPollRec, next));
+ g_slice_free_chain (GPollRec, list, next);
}
/**
slab_allocator_free_chunk (chunk_size, mem_block);
g_mutex_unlock (allocator->slab_mutex);
}
- else /* delegate to system malloc */
+ else /* delegate to system malloc */
g_free (mem_block);
}
void
-g_slice_free_chain (gsize mem_size,
- gpointer mem_chain,
- gsize next_offset)
-{
- GSList *slice = mem_chain;
- g_return_if_fail (next_offset == G_STRUCT_OFFSET (GSList, next));
- g_return_if_fail (mem_size >= sizeof (GSList));
- while (slice)
- {
- GSList *current = slice;
- slice = slice->next;
- g_slice_free1 (mem_size, current);
- }
+g_slice_free_chain_with_offset (gsize mem_size,
+ gpointer mem_chain,
+ gsize next_offset)
+{
+ gpointer slice = mem_chain;
/* while the thread magazines and the magazine cache are implemented so that
* they can easily be extended to allow for free lists containing more free
* lists for the first level nodes, which would allow O(1) freeing in this
* - memory usage histograms on larger applications seem to indicate that
* the amount of released multi node lists is negligible in comparison
* to single node releases.
+ * - the major performance bottle neck, namely g_private_get() or
+ * g_mutex_lock()/g_mutex_unlock() has already been moved out of the
+ * inner loop for freeing chained slices.
*/
+ gsize chunk_size = P2ALIGN (mem_size);
+ guint acat = allocator_categorize (chunk_size);
+ if (G_LIKELY (acat == 1)) /* allocate through magazine layer */
+ {
+ ThreadMemory *tmem = thread_memory_from_self();
+ guint ix = SLAB_INDEX (allocator, chunk_size);
+ while (slice)
+ {
+ guint8 *current = slice;
+ slice = *(gpointer*) (current + next_offset);
+ if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+ {
+ thread_memory_swap_magazines (tmem, ix);
+ if (G_UNLIKELY (thread_memory_magazine2_is_full (tmem, ix)))
+ thread_memory_magazine2_unload (tmem, ix);
+ }
+ thread_memory_magazine2_free (tmem, ix, current);
+ }
+ }
+ else if (acat == 2) /* allocate through slab allocator */
+ {
+ g_mutex_lock (allocator->slab_mutex);
+ while (slice)
+ {
+ guint8 *current = slice;
+ slice = *(gpointer*) (current + next_offset);
+ slab_allocator_free_chunk (chunk_size, current);
+ }
+ g_mutex_unlock (allocator->slab_mutex);
+ }
+ else /* delegate to system malloc */
+ while (slice)
+ {
+ guint8 *current = slice;
+ slice = *(gpointer*) (current + next_offset);
+ g_free (current);
+ }
}
/* --- single page allocator --- */
/* slices - fast allocation/release of small memory blocks
*/
-gpointer g_slice_alloc (gsize block_size) G_GNUC_MALLOC;
-gpointer g_slice_alloc0 (gsize block_size) G_GNUC_MALLOC;
-void g_slice_free1 (gsize block_size,
- gpointer mem_block);
-void g_slice_free_chain (gsize block_size,
- gpointer mem_chain,
- gsize next_offset);
+gpointer g_slice_alloc (gsize block_size) G_GNUC_MALLOC;
+gpointer g_slice_alloc0 (gsize block_size) G_GNUC_MALLOC;
+void g_slice_free1 (gsize block_size,
+ gpointer mem_block);
+void g_slice_free_chain_with_offset (gsize block_size,
+ gpointer mem_chain,
+ gsize next_offset);
#define g_slice_new(type) ((type*) g_slice_alloc (sizeof (type)))
#define g_slice_new0(type) ((type*) g_slice_alloc0 (sizeof (type)))
-/* g_slice_free(type,mem) g_slice_free1 (sizeof (type), mem) */
+/* g_slice_free (MemoryBlockType,
+ * MemoryBlockType *mem_block);
+ * g_slice_free_chain (MemoryBlockType,
+ * MemoryBlockType *first_chain_block,
+ * memory_block_next_field);
+ * pseudo prototypes for the macro
+ * definitions following below.
+ */
+
+/* we go through extra hoops to ensure type safety */
+#define g_slice_free(type, mem) do { \
+ if (1) g_slice_free1 (sizeof (type), (mem)); \
+ else (void) ((type*) 0 == (mem)); \
+} while (0)
+#define g_slice_free_chain(type, mem_chain, next) do { \
+ if (1) g_slice_free_chain_with_offset (sizeof (type), \
+ (mem_chain), G_STRUCT_OFFSET (type, next)); \
+ else (void) ((type*) 0 == (mem_chain)); \
+} while (0)
-#if __GNUC__ >= 2
-/* for GCC, define a type-safe variant of g_slice_free() */
-#define g_slice_free(type, mem) ({ \
- void (*g_slice_free) (gsize, type*); \
- while (0) g_slice_free (sizeof (type), mem); \
- g_slice_free1 (sizeof (type), mem); \
-})
-#else /* !__GNUC__ */
-#define g_slice_free(type, mem) g_slice_free1 (sizeof (type) + (gsize) (type*) 0, mem)
-/* we go through the extra (gsize)(type*)0 hoop to ensure a known type argument */
-#endif /* !__GNUC__ */
/* --- internal debugging API --- */
typedef enum {
void
g_slist_free (GSList *slist)
{
- g_slice_free_chain (sizeof (GSList), slist, G_STRUCT_OFFSET (GSList, next));
+ g_slice_free_chain (GSList, slist, next);
}
void