mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-02 07:36:17 +01:00
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:
parent
559e1057a0
commit
6ed79b115c
20
ChangeLog
20
ChangeLog
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 --- */
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user