From: Tim Janik Date: Mon, 5 Dec 2005 15:01:27 +0000 (+0000) Subject: implement chain walking for arbitrary ->next pointer offsets in X-Git-Url: http://git.openbox.org/?a=commitdiff_plain;h=6ed79b115c311323be086e2581650c33366c6f37;p=dana%2Fcg-glib.git implement chain walking for arbitrary ->next pointer offsets in Mon Dec 5 15:53:20 2005 Tim Janik * 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 . * glib/gmain.c: * glib/glist.c: * glib/gslist.c: * glib/glib.symbols: s/g_slice_free_chain/g_slice_free_chain_with_offset/ --- diff --git a/ChangeLog b/ChangeLog index 9a22a33b..f35cc7f1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Mon Dec 5 15:53:20 2005 Tim Janik + + * 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 . + + * 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 * glib/gasyncqueue.c: Add some docs. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 9a22a33b..f35cc7f1 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,23 @@ +Mon Dec 5 15:53:20 2005 Tim Janik + + * 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 . + + * 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 * glib/gasyncqueue.c: Add some docs. diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 9a22a33b..f35cc7f1 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,3 +1,23 @@ +Mon Dec 5 15:53:20 2005 Tim Janik + + * 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 . + + * 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 * glib/gasyncqueue.c: Add some docs. diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 3fad9811..7f3346ff 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,8 @@ +Mon Dec 5 15:53:37 2005 Tim Janik + + * glib/tmpl/memory_slices.sgml: updates to new g_slice API + and minor fixes. + 2005-12-05 Matthias Clasen * gobject/tmpl/generic_values.sgml: diff --git a/docs/reference/glib/tmpl/memory_slices.sgml b/docs/reference/glib/tmpl/memory_slices.sgml index 790a7d0f..643dd4cc 100644 --- a/docs/reference/glib/tmpl/memory_slices.sgml +++ b/docs/reference/glib/tmpl/memory_slices.sgml @@ -6,18 +6,21 @@ efficient way to allocate groups of equal-sized chunks of memory. -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. To achieve these goals, the slice allocator uses a sophisticated, layered design that has been inspired by Bonwick's slab allocator -[Bonwick94] Jeff Bonwick, The slab allocator: An object-caching kernel + +[Bonwick94] Jeff Bonwick, The slab allocator: An object-caching kernel memory allocator. USENIX 1994, and - [Bonwick01] Bonwick and Jonathan Adams, Magazines and vmem: Extending the -slab allocator to many cpu's and arbitrary resources. USENIX 2001. +[Bonwick01] Bonwick and Jonathan Adams, Magazines and vmem: Extending the +slab allocator to many cpu's and arbitrary resources. USENIX 2001 +. 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. @@ -94,17 +97,19 @@ object size used at allocation time is still available when freeing. 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*). @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 -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. @block_size: the number of bytes to allocate @@ -114,38 +119,48 @@ memory to 0. -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. @block_size: the size of the block @mem_block: a pointer to the block to free @Since: 2.10 - + -Frees a linked list of memory block. The memory blocks must be equal-sized, -allocated from the slice allocator and linked together by a -next 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 next 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. - -Currently, this function only supports blocks which store their -next pointer in the same position as #GSList. -Therefore, @next_offset must be 1. - - @block_size: the size of the blocks @mem_chain: a pointer to the first block @next_offset: the offset of the next pointer @Since: 2.10 + + +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. + +@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 + 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. @type: the type to allocate, typically a structure name @@ -156,9 +171,9 @@ the given type, avoiding a type cast in the source code. 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. @type: the type to allocate, typically a structure name diff --git a/glib/glib.symbols b/glib/glib.symbols index aec5e494..bfbb560d 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -608,7 +608,7 @@ g_blow_chunks 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 diff --git a/glib/glist.c b/glib/glist.c index 1e9a96f9..9f756b50 100644 --- a/glib/glist.c +++ b/glib/glist.c @@ -49,7 +49,7 @@ g_list_alloc (void) 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 diff --git a/glib/gmain.c b/glib/gmain.c index e3a47b79..0595015d 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -189,7 +189,7 @@ struct _GChildWatchSource struct _GPollRec { GPollFD *fd; - GPollRec *next; /* chaining via second pointer member allows use of g_slice_free_chain() */ + GPollRec *next; gint priority; }; @@ -599,7 +599,7 @@ static inline void 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); } /** diff --git a/glib/gslice.c b/glib/gslice.c index ddc3ddc3..683d2be2 100644 --- a/glib/gslice.c +++ b/glib/gslice.c @@ -772,24 +772,16 @@ g_slice_free1 (gsize mem_size, 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 @@ -801,7 +793,47 @@ g_slice_free_chain (gsize mem_size, * - 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 --- */ diff --git a/glib/gslice.h b/glib/gslice.h index 4a9cbda9..a3201481 100644 --- a/glib/gslice.h +++ b/glib/gslice.h @@ -29,28 +29,35 @@ G_BEGIN_DECLS /* 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 { diff --git a/glib/gslist.c b/glib/gslist.c index 6483f07b..ebf03483 100644 --- a/glib/gslist.c +++ b/glib/gslist.c @@ -49,7 +49,7 @@ g_slist_alloc (void) 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