From 27312762698cb473837779b4e8dc59afdafe262c Mon Sep 17 00:00:00 2001 From: Tim Janik Date: Fri, 2 Dec 2005 09:57:06 +0000 Subject: [PATCH] extended to perform the benchmarking on the old memchunk code if 'O' is Fri Dec 2 10:55:07 2005 Tim Janik * tests/slice-test.c: extended to perform the benchmarking on the old memchunk code if 'O' is selected. * tests/memchunks.c: new file which contains the old GLib mem chunks implementation with prefix old_mem_chunk_. * tests/Makefile.am: added memchunks.c --- tests/Makefile.am | 1 + tests/memchunks.c | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/slice-test.c | 157 ++++++++++++-- 3 files changed, 748 insertions(+), 22 deletions(-) create mode 100644 tests/memchunks.c diff --git a/tests/Makefile.am b/tests/Makefile.am index 03c050b..445cabb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -150,6 +150,7 @@ rand_test_LDADD = $(progs_ldadd) relation_test_LDADD = $(progs_ldadd) shell_test_LDADD = $(progs_ldadd) slist_test_LDADD = $(progs_ldadd) +slice_test_SOURCES = slice-test.c memchunks.c slice_test_LDADD = $(thread_ldadd) spawn_test_LDADD = $(progs_ldadd) strfunc_test_LDADD = $(progs_ldadd) diff --git a/tests/memchunks.c b/tests/memchunks.c new file mode 100644 index 0000000..7a08de0 --- /dev/null +++ b/tests/memchunks.c @@ -0,0 +1,612 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * MT safe + */ + +#include "config.h" + +#include +#include +#include + +#include "glib.h" + +/* notes on macros: + * if ENABLE_GC_FRIENDLY is defined, freed memory should be 0-wiped. + */ + +#define MEM_PROFILE_TABLE_SIZE 4096 + +#define MEM_AREA_SIZE 4L + +static guint mem_chunk_recursion = 0; +# define MEM_CHUNK_ROUTINE_COUNT() (mem_chunk_recursion) +# define ENTER_MEM_CHUNK_ROUTINE() (mem_chunk_recursion = MEM_CHUNK_ROUTINE_COUNT () + 1) +# define LEAVE_MEM_CHUNK_ROUTINE() (mem_chunk_recursion = MEM_CHUNK_ROUTINE_COUNT () - 1) + +/* --- old memchunk prototypes --- */ +void old_mem_chunks_init (void); +GMemChunk* old_mem_chunk_new (const gchar *name, + gint atom_size, + gulong area_size, + gint type); +void old_mem_chunk_destroy (GMemChunk *mem_chunk); +gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk); +gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk); +void old_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem); +void old_mem_chunk_clean (GMemChunk *mem_chunk); +void old_mem_chunk_reset (GMemChunk *mem_chunk); +void old_mem_chunk_print (GMemChunk *mem_chunk); +void old_mem_chunk_info (void); + + +/* --- MemChunks --- */ +#ifndef G_ALLOC_AND_FREE +typedef struct _GAllocator GAllocator; +typedef struct _GMemChunk GMemChunk; +#define G_ALLOC_ONLY 1 +#define G_ALLOC_AND_FREE 2 +#endif + +typedef struct _GFreeAtom GFreeAtom; +typedef struct _GMemArea GMemArea; + +struct _GFreeAtom +{ + GFreeAtom *next; +}; + +struct _GMemArea +{ + GMemArea *next; /* the next mem area */ + GMemArea *prev; /* the previous mem area */ + gulong index; /* the current index into the "mem" array */ + gulong free; /* the number of free bytes in this mem area */ + gulong allocated; /* the number of atoms allocated from this area */ + gulong mark; /* is this mem area marked for deletion */ + gchar mem[MEM_AREA_SIZE]; /* the mem array from which atoms get allocated + * the actual size of this array is determined by + * the mem chunk "area_size". ANSI says that it + * must be declared to be the maximum size it + * can possibly be (even though the actual size + * may be less). + */ +}; + +struct _GMemChunk +{ + const gchar *name; /* name of this MemChunk...used for debugging output */ + gint type; /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */ + gint num_mem_areas; /* the number of memory areas */ + gint num_marked_areas; /* the number of areas marked for deletion */ + guint atom_size; /* the size of an atom */ + gulong area_size; /* the size of a memory area */ + GMemArea *mem_area; /* the current memory area */ + GMemArea *mem_areas; /* a list of all the mem areas owned by this chunk */ + GMemArea *free_mem_area; /* the free area...which is about to be destroyed */ + GFreeAtom *free_atoms; /* the free atoms list */ + GTree *mem_tree; /* tree of mem areas sorted by memory address */ + GMemChunk *next; /* pointer to the next chunk */ + GMemChunk *prev; /* pointer to the previous chunk */ +}; + + +static gulong old_mem_chunk_compute_size (gulong size, + gulong min_size) G_GNUC_CONST; +static gint old_mem_chunk_area_compare (GMemArea *a, + GMemArea *b); +static gint old_mem_chunk_area_search (GMemArea *a, + gchar *addr); + +/* here we can't use StaticMutexes, as they depend upon a working + * g_malloc, the same holds true for StaticPrivate + */ +static GMutex *mem_chunks_lock = NULL; +static GMemChunk *mem_chunks = NULL; + +void +old_mem_chunks_init (void) +{ + mem_chunks_lock = g_mutex_new (); +} + +GMemChunk* +old_mem_chunk_new (const gchar *name, + gint atom_size, + gulong area_size, + gint type) +{ + GMemChunk *mem_chunk; + gulong rarea_size; + + g_return_val_if_fail (atom_size > 0, NULL); + g_return_val_if_fail (area_size >= atom_size, NULL); + + ENTER_MEM_CHUNK_ROUTINE (); + + area_size = (area_size + atom_size - 1) / atom_size; + area_size *= atom_size; + + mem_chunk = g_new (GMemChunk, 1); + mem_chunk->name = name; + mem_chunk->type = type; + mem_chunk->num_mem_areas = 0; + mem_chunk->num_marked_areas = 0; + mem_chunk->mem_area = NULL; + mem_chunk->free_mem_area = NULL; + mem_chunk->free_atoms = NULL; + mem_chunk->mem_tree = NULL; + mem_chunk->mem_areas = NULL; + mem_chunk->atom_size = atom_size; + + if (mem_chunk->type == G_ALLOC_AND_FREE) + mem_chunk->mem_tree = g_tree_new ((GCompareFunc) old_mem_chunk_area_compare); + + if (mem_chunk->atom_size % G_MEM_ALIGN) + mem_chunk->atom_size += G_MEM_ALIGN - (mem_chunk->atom_size % G_MEM_ALIGN); + + rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE; + rarea_size = old_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE); + mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE); + + g_mutex_lock (mem_chunks_lock); + mem_chunk->next = mem_chunks; + mem_chunk->prev = NULL; + if (mem_chunks) + mem_chunks->prev = mem_chunk; + mem_chunks = mem_chunk; + g_mutex_unlock (mem_chunks_lock); + + LEAVE_MEM_CHUNK_ROUTINE (); + + return mem_chunk; +} + +void +old_mem_chunk_destroy (GMemChunk *mem_chunk) +{ + GMemArea *mem_areas; + GMemArea *temp_area; + + g_return_if_fail (mem_chunk != NULL); + + ENTER_MEM_CHUNK_ROUTINE (); + + mem_areas = mem_chunk->mem_areas; + while (mem_areas) + { + temp_area = mem_areas; + mem_areas = mem_areas->next; + g_free (temp_area); + } + + g_mutex_lock (mem_chunks_lock); + if (mem_chunk->next) + mem_chunk->next->prev = mem_chunk->prev; + if (mem_chunk->prev) + mem_chunk->prev->next = mem_chunk->next; + + if (mem_chunk == mem_chunks) + mem_chunks = mem_chunks->next; + g_mutex_unlock (mem_chunks_lock); + + if (mem_chunk->type == G_ALLOC_AND_FREE) + g_tree_destroy (mem_chunk->mem_tree); + + g_free (mem_chunk); + + LEAVE_MEM_CHUNK_ROUTINE (); +} + +gpointer +old_mem_chunk_alloc (GMemChunk *mem_chunk) +{ + GMemArea *temp_area; + gpointer mem; + + ENTER_MEM_CHUNK_ROUTINE (); + + g_return_val_if_fail (mem_chunk != NULL, NULL); + + while (mem_chunk->free_atoms) + { + /* Get the first piece of memory on the "free_atoms" list. + * We can go ahead and destroy the list node we used to keep + * track of it with and to update the "free_atoms" list to + * point to its next element. + */ + mem = mem_chunk->free_atoms; + mem_chunk->free_atoms = mem_chunk->free_atoms->next; + + /* Determine which area this piece of memory is allocated from */ + temp_area = g_tree_search (mem_chunk->mem_tree, + (GCompareFunc) old_mem_chunk_area_search, + mem); + + /* If the area has been marked, then it is being destroyed. + * (ie marked to be destroyed). + * We check to see if all of the segments on the free list that + * reference this area have been removed. This occurs when + * the ammount of free memory is less than the allocatable size. + * If the chunk should be freed, then we place it in the "free_mem_area". + * This is so we make sure not to free the mem area here and then + * allocate it again a few lines down. + * If we don't allocate a chunk a few lines down then the "free_mem_area" + * will be freed. + * If there is already a "free_mem_area" then we'll just free this mem area. + */ + if (temp_area->mark) + { + /* Update the "free" memory available in that area */ + temp_area->free += mem_chunk->atom_size; + + if (temp_area->free == mem_chunk->area_size) + { + if (temp_area == mem_chunk->mem_area) + mem_chunk->mem_area = NULL; + + if (mem_chunk->free_mem_area) + { + mem_chunk->num_mem_areas -= 1; + + if (temp_area->next) + temp_area->next->prev = temp_area->prev; + if (temp_area->prev) + temp_area->prev->next = temp_area->next; + if (temp_area == mem_chunk->mem_areas) + mem_chunk->mem_areas = mem_chunk->mem_areas->next; + + if (mem_chunk->type == G_ALLOC_AND_FREE) + g_tree_remove (mem_chunk->mem_tree, temp_area); + g_free (temp_area); + } + else + mem_chunk->free_mem_area = temp_area; + + mem_chunk->num_marked_areas -= 1; + } + } + else + { + /* Update the number of allocated atoms count. + */ + temp_area->allocated += 1; + + /* The area wasn't marked...return the memory + */ + goto outa_here; + } + } + + /* If there isn't a current mem area or the current mem area is out of space + * then allocate a new mem area. We'll first check and see if we can use + * the "free_mem_area". Otherwise we'll just malloc the mem area. + */ + if ((!mem_chunk->mem_area) || + ((mem_chunk->mem_area->index + mem_chunk->atom_size) > mem_chunk->area_size)) + { + if (mem_chunk->free_mem_area) + { + mem_chunk->mem_area = mem_chunk->free_mem_area; + mem_chunk->free_mem_area = NULL; + } + else + { +#ifdef ENABLE_GC_FRIENDLY + mem_chunk->mem_area = (GMemArea*) g_malloc0 (sizeof (GMemArea) - + MEM_AREA_SIZE + + mem_chunk->area_size); +#else /* !ENABLE_GC_FRIENDLY */ + mem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) - + MEM_AREA_SIZE + + mem_chunk->area_size); +#endif /* ENABLE_GC_FRIENDLY */ + + mem_chunk->num_mem_areas += 1; + mem_chunk->mem_area->next = mem_chunk->mem_areas; + mem_chunk->mem_area->prev = NULL; + + if (mem_chunk->mem_areas) + mem_chunk->mem_areas->prev = mem_chunk->mem_area; + mem_chunk->mem_areas = mem_chunk->mem_area; + + if (mem_chunk->type == G_ALLOC_AND_FREE) + g_tree_insert (mem_chunk->mem_tree, mem_chunk->mem_area, mem_chunk->mem_area); + } + + mem_chunk->mem_area->index = 0; + mem_chunk->mem_area->free = mem_chunk->area_size; + mem_chunk->mem_area->allocated = 0; + mem_chunk->mem_area->mark = 0; + } + + /* Get the memory and modify the state variables appropriately. + */ + mem = (gpointer) &mem_chunk->mem_area->mem[mem_chunk->mem_area->index]; + mem_chunk->mem_area->index += mem_chunk->atom_size; + mem_chunk->mem_area->free -= mem_chunk->atom_size; + mem_chunk->mem_area->allocated += 1; + + outa_here: + + LEAVE_MEM_CHUNK_ROUTINE (); + + return mem; +} + +gpointer +old_mem_chunk_alloc0 (GMemChunk *mem_chunk) +{ + gpointer mem; + + mem = old_mem_chunk_alloc (mem_chunk); + if (mem) + { + memset (mem, 0, mem_chunk->atom_size); + } + + return mem; +} + +void +old_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem) +{ + GMemArea *temp_area; + GFreeAtom *free_atom; + + g_return_if_fail (mem_chunk != NULL); + g_return_if_fail (mem != NULL); + + ENTER_MEM_CHUNK_ROUTINE (); + +#ifdef ENABLE_GC_FRIENDLY + memset (mem, 0, mem_chunk->atom_size); +#endif /* ENABLE_GC_FRIENDLY */ + + /* Don't do anything if this is an ALLOC_ONLY chunk + */ + if (mem_chunk->type == G_ALLOC_AND_FREE) + { + /* Place the memory on the "free_atoms" list + */ + free_atom = (GFreeAtom*) mem; + free_atom->next = mem_chunk->free_atoms; + mem_chunk->free_atoms = free_atom; + + temp_area = g_tree_search (mem_chunk->mem_tree, + (GCompareFunc) old_mem_chunk_area_search, + mem); + + temp_area->allocated -= 1; + + if (temp_area->allocated == 0) + { + temp_area->mark = 1; + mem_chunk->num_marked_areas += 1; + } + } + + LEAVE_MEM_CHUNK_ROUTINE (); +} + +/* This doesn't free the free_area if there is one */ +void +old_mem_chunk_clean (GMemChunk *mem_chunk) +{ + GMemArea *mem_area; + GFreeAtom *prev_free_atom; + GFreeAtom *temp_free_atom; + gpointer mem; + + g_return_if_fail (mem_chunk != NULL); + + ENTER_MEM_CHUNK_ROUTINE (); + + if (mem_chunk->type == G_ALLOC_AND_FREE) + { + prev_free_atom = NULL; + temp_free_atom = mem_chunk->free_atoms; + + while (temp_free_atom) + { + mem = (gpointer) temp_free_atom; + + mem_area = g_tree_search (mem_chunk->mem_tree, + (GCompareFunc) old_mem_chunk_area_search, + mem); + + /* If this mem area is marked for destruction then delete the + * area and list node and decrement the free mem. + */ + if (mem_area->mark) + { + if (prev_free_atom) + prev_free_atom->next = temp_free_atom->next; + else + mem_chunk->free_atoms = temp_free_atom->next; + temp_free_atom = temp_free_atom->next; + + mem_area->free += mem_chunk->atom_size; + if (mem_area->free == mem_chunk->area_size) + { + mem_chunk->num_mem_areas -= 1; + mem_chunk->num_marked_areas -= 1; + + if (mem_area->next) + mem_area->next->prev = mem_area->prev; + if (mem_area->prev) + mem_area->prev->next = mem_area->next; + if (mem_area == mem_chunk->mem_areas) + mem_chunk->mem_areas = mem_chunk->mem_areas->next; + if (mem_area == mem_chunk->mem_area) + mem_chunk->mem_area = NULL; + + if (mem_chunk->type == G_ALLOC_AND_FREE) + g_tree_remove (mem_chunk->mem_tree, mem_area); + g_free (mem_area); + } + } + else + { + prev_free_atom = temp_free_atom; + temp_free_atom = temp_free_atom->next; + } + } + } + LEAVE_MEM_CHUNK_ROUTINE (); +} + +void +old_mem_chunk_reset (GMemChunk *mem_chunk) +{ + GMemArea *mem_areas; + GMemArea *temp_area; + + g_return_if_fail (mem_chunk != NULL); + + ENTER_MEM_CHUNK_ROUTINE (); + + mem_areas = mem_chunk->mem_areas; + mem_chunk->num_mem_areas = 0; + mem_chunk->mem_areas = NULL; + mem_chunk->mem_area = NULL; + + while (mem_areas) + { + temp_area = mem_areas; + mem_areas = mem_areas->next; + g_free (temp_area); + } + + mem_chunk->free_atoms = NULL; + + if (mem_chunk->mem_tree) + { + g_tree_destroy (mem_chunk->mem_tree); + mem_chunk->mem_tree = g_tree_new ((GCompareFunc) old_mem_chunk_area_compare); + } + + LEAVE_MEM_CHUNK_ROUTINE (); +} + +void +old_mem_chunk_print (GMemChunk *mem_chunk) +{ + GMemArea *mem_areas; + gulong mem; + + g_return_if_fail (mem_chunk != NULL); + + mem_areas = mem_chunk->mem_areas; + mem = 0; + + while (mem_areas) + { + mem += mem_chunk->area_size - mem_areas->free; + mem_areas = mem_areas->next; + } + + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, + "%s: %ld bytes using %d mem areas", + mem_chunk->name, mem, mem_chunk->num_mem_areas); +} + +void +old_mem_chunk_info (void) +{ + GMemChunk *mem_chunk; + gint count; + + count = 0; + g_mutex_lock (mem_chunks_lock); + mem_chunk = mem_chunks; + while (mem_chunk) + { + count += 1; + mem_chunk = mem_chunk->next; + } + g_mutex_unlock (mem_chunks_lock); + + g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, "%d mem chunks", count); + + g_mutex_lock (mem_chunks_lock); + mem_chunk = mem_chunks; + g_mutex_unlock (mem_chunks_lock); + + while (mem_chunk) + { + old_mem_chunk_print ((GMemChunk*) mem_chunk); + mem_chunk = mem_chunk->next; + } +} + +static gulong +old_mem_chunk_compute_size (gulong size, + gulong min_size) +{ + gulong power_of_2; + gulong lower, upper; + + power_of_2 = 16; + while (power_of_2 < size) + power_of_2 <<= 1; + + lower = power_of_2 >> 1; + upper = power_of_2; + + if (size - lower < upper - size && lower >= min_size) + return lower; + else + return upper; +} + +static gint +old_mem_chunk_area_compare (GMemArea *a, + GMemArea *b) +{ + if (a->mem > b->mem) + return 1; + else if (a->mem < b->mem) + return -1; + return 0; +} + +static gint +old_mem_chunk_area_search (GMemArea *a, + gchar *addr) +{ + if (a->mem <= addr) + { + if (addr < &a->mem[a->index]) + return 0; + return 1; + } + return -1; +} diff --git a/tests/slice-test.c b/tests/slice-test.c index fd70143..fbbd081 100644 --- a/tests/slice-test.c +++ b/tests/slice-test.c @@ -23,7 +23,109 @@ #include // gettimeofday #define quick_rand32() (rand_accu = 1664525 * rand_accu + 1013904223, rand_accu) -static guint prime_size = 1021; // 769; // 509 +static guint prime_size = 1021; // 769; // 509 +static gboolean clean_memchunks = FALSE; +static guint number_of_blocks = 10000; /* total number of blocks allocated */ +static guint number_of_repetitions = 10000; /* number of alloc+free repetitions */ + +/* --- old memchunk prototypes (memchunks.c) --- */ +void old_mem_chunks_init (void); +GMemChunk* old_mem_chunk_new (const gchar *name, + gint atom_size, + gulong area_size, + gint type); +void old_mem_chunk_destroy (GMemChunk *mem_chunk); +gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk); +gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk); +void old_mem_chunk_free (GMemChunk *mem_chunk, + gpointer mem); +void old_mem_chunk_clean (GMemChunk *mem_chunk); +void old_mem_chunk_reset (GMemChunk *mem_chunk); +void old_mem_chunk_print (GMemChunk *mem_chunk); +void old_mem_chunk_info (void); +#ifndef G_ALLOC_AND_FREE +#define G_ALLOC_AND_FREE 2 +#endif + +/* --- functions --- */ +static inline gpointer +memchunk_alloc (GMemChunk **memchunkp, + guint size) +{ + size = MAX (size, 1); + if (G_UNLIKELY (!*memchunkp)) + *memchunkp = old_mem_chunk_new ("", size, 4096, G_ALLOC_AND_FREE); + return old_mem_chunk_alloc (*memchunkp); +} + +static inline void +memchunk_free (GMemChunk *memchunk, + gpointer chunk) +{ + old_mem_chunk_free (memchunk, chunk); + if (clean_memchunks) + old_mem_chunk_clean (memchunk); +} + +static gpointer +test_memchunk_thread (gpointer data) +{ + guint32 rand_accu = 2147483563; + /* initialize random numbers */ + if (data) + rand_accu = *(guint32*) data; + else + { + struct timeval rand_tv; + gettimeofday (&rand_tv, NULL); + rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16); + } + + /* prepare for memchunk creation */ + GMemChunk **memchunks = g_alloca (sizeof (memchunks[0]) * prime_size); + memset (memchunks, 0, sizeof (memchunks[0]) * prime_size); + + guint i, j; + guint8 **ps = g_new (guint8*, number_of_blocks); + guint *ss = g_new (guint, number_of_blocks); + /* create number_of_blocks random sizes */ + for (i = 0; i < number_of_blocks; i++) + ss[i] = quick_rand32() % prime_size; + /* allocate number_of_blocks blocks */ + for (i = 0; i < number_of_blocks; i++) + ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]); + for (j = 0; j < number_of_repetitions; j++) + { + /* free number_of_blocks/2 blocks */ + for (i = 0; i < number_of_blocks; i += 2) + memchunk_free (memchunks[ss[i]], ps[i]); + /* allocate number_of_blocks/2 blocks with new sizes */ + for (i = 0; i < number_of_blocks; i += 2) + { + ss[i] = quick_rand32() % prime_size; + ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]); + } + } + /* free number_of_blocks blocks */ + for (i = 0; i < number_of_blocks; i++) + memchunk_free (memchunks[ss[i]], ps[i]); + /* alloc and free many equally sized chunks in a row */ + for (i = 0; i < number_of_repetitions; i++) + { + guint sz = quick_rand32() % prime_size; + guint k = number_of_blocks / 100; + for (j = 0; j < k; j++) + ps[j] = memchunk_alloc (&memchunks[sz], sz); + for (j = 0; j < k; j++) + memchunk_free (memchunks[sz], ps[j]); + } + /* cleanout memchunks */ + for (i = 0; i < prime_size; i++) + if (memchunks[i]) + old_mem_chunk_destroy (memchunks[i]); + + return NULL; +} static gpointer test_sliced_mem_thread (gpointer data) @@ -39,36 +141,35 @@ test_sliced_mem_thread (gpointer data) rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16); } - guint i, m = 10000; /* number of blocks */ - guint j, n = 10000; /* number of alloc+free repetitions */ - guint8 **ps = g_new (guint8*, m); - guint *ss = g_new (guint, m); - /* create m random sizes */ - for (i = 0; i < m; i++) + guint i, j; + guint8 **ps = g_new (guint8*, number_of_blocks); + guint *ss = g_new (guint, number_of_blocks); + /* create number_of_blocks random sizes */ + for (i = 0; i < number_of_blocks; i++) ss[i] = quick_rand32() % prime_size; - /* allocate m blocks */ - for (i = 0; i < m; i++) + /* allocate number_of_blocks blocks */ + for (i = 0; i < number_of_blocks; i++) ps[i] = g_slice_alloc (ss[i]); - for (j = 0; j < n; j++) + for (j = 0; j < number_of_repetitions; j++) { - /* free m/2 blocks */ - for (i = 0; i < m; i += 2) + /* free number_of_blocks/2 blocks */ + for (i = 0; i < number_of_blocks; i += 2) g_slice_free1 (ss[i], ps[i]); - /* allocate m/2 blocks with new sizes */ - for (i = 0; i < m; i += 2) + /* allocate number_of_blocks/2 blocks with new sizes */ + for (i = 0; i < number_of_blocks; i += 2) { ss[i] = quick_rand32() % prime_size; ps[i] = g_slice_alloc (ss[i]); } } - /* free m blocks */ - for (i = 0; i < m; i++) + /* free number_of_blocks blocks */ + for (i = 0; i < number_of_blocks; i++) g_slice_free1 (ss[i], ps[i]); /* alloc and free many equally sized chunks in a row */ - for (i = 0; i < n; i++) + for (i = 0; i < number_of_repetitions; i++) { guint sz = quick_rand32() % prime_size; - guint k = m / 100; + guint k = number_of_blocks / 100; for (j = 0; j < k; j++) ps[j] = g_slice_alloc (sz); for (j = 0; j < k; j++) @@ -81,7 +182,7 @@ test_sliced_mem_thread (gpointer data) static void usage (void) { - g_print ("Usage: gslicedmemory [n_threads] [G|S|M][f][c] [maxblocksize] [seed]\n"); + g_print ("Usage: gslicedmemory [n_threads] [G|S|M|O][f][c] [maxblocksize] [seed]\n"); } int @@ -89,7 +190,7 @@ main (int argc, char *argv[]) { guint seed32, *seedp = NULL; - gboolean ccounters = FALSE; + gboolean ccounters = FALSE, use_memchunks = FALSE; guint n_threads = 1; const gchar *mode = "slab allocator + magazine cache", *emode = " "; if (argc > 1) @@ -114,8 +215,13 @@ main (int argc, g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE); mode = "system malloc"; break; + case 'O': /* old memchunks */ + use_memchunks = TRUE; + mode = "old memchunks"; + break; case 'f': /* eager freeing */ g_slice_set_config (G_SLICE_CONFIG_ALWAYS_FREE, TRUE); + clean_memchunks = TRUE; emode = " with eager freeing"; break; case 'c': /* print contention counters */ @@ -146,8 +252,15 @@ main (int argc, GThread *threads[n_threads]; guint i; - for (i = 0; i < n_threads; i++) - threads[i] = g_thread_create_full (test_sliced_mem_thread, seedp, 0, TRUE, FALSE, 0, NULL); + if (!use_memchunks) + for (i = 0; i < n_threads; i++) + threads[i] = g_thread_create_full (test_sliced_mem_thread, seedp, 0, TRUE, FALSE, 0, NULL); + else + { + old_mem_chunks_init(); + for (i = 0; i < n_threads; i++) + threads[i] = g_thread_create_full (test_memchunk_thread, seedp, 0, TRUE, FALSE, 0, NULL); + } for (i = 0; i < n_threads; i++) g_thread_join (threads[i]); -- 2.7.4