implement chain walking for arbitrary ->next pointer offsets in

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/
This commit is contained in:
Tim Janik 2005-12-05 15:01:27 +00:00 committed by Tim Janik
parent 559e1057a0
commit 6ed79b115c
11 changed files with 183 additions and 64 deletions

View File

@ -1,3 +1,23 @@
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.

View File

@ -1,3 +1,23 @@
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.

View File

@ -1,3 +1,23 @@
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.

View File

@ -1,3 +1,8 @@
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:

View File

@ -6,18 +6,21 @@ efficient way to allocate groups of equal-sized chunks of memory.
<!-- ##### 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.
@ -94,17 +97,19 @@ object size used at allocation time is still available when freeing.
<!-- ##### 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
@ -114,38 +119,48 @@ memory to 0.
<!-- ##### 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
@ -156,9 +171,9 @@ the given type, avoiding a type cast in the source code.
<!-- ##### 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

View File

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

View File

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

View File

@ -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);
}
/**

View File

@ -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)
g_slice_free_chain_with_offset (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);
}
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 --- */

View File

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

View File

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