diff -r e4d67989cc36 -r 47c74d1534e1 glib/tests/slice-test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/glib/tests/slice-test.c Fri Apr 16 16:46:38 2010 +0300 @@ -0,0 +1,318 @@ +/* GLIB sliced memory - fast threaded memory chunk allocator + * Copyright (C) 2005 Tim Janik + * Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. + * 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. + */ +#include + +#include +#include +#ifdef __SYMBIAN32__ +#include "mrt2_glib2_test.h" +#endif /*__SYMBIAN32__*/ +#define quick_rand32() (rand_accu = 1664525 * rand_accu + 1013904223, rand_accu) +static guint prime_size = 1021; // 769; // 509 +static gboolean clean_memchunks = FALSE; +static guint number_of_blocks = 100; /* total number of blocks allocated */ +static guint number_of_repetitions = 100; /* number of alloc+free repetitions */ +static gboolean want_corruption = FALSE; + +/* --- 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 int +corruption (void) +{ + if (G_UNLIKELY (want_corruption)) + { + /* corruption per call likelyness is about 1:4000000 */ + guint32 r = g_random_int() % 8000009; + return r == 277 ? +1 : r == 281 ? -1 : 0; + } + return 0; +} + +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) +{ + GMemChunk **memchunks; + guint i, j; + guint8 **ps; + guint *ss; + guint32 rand_accu = 2147483563; + /* initialize random numbers */ + if (data) + rand_accu = *(guint32*) data; + else + { + GTimeVal rand_tv; + g_get_current_time (&rand_tv); + rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16); + } + + /* prepare for memchunk creation */ + memchunks = (GMemChunk **)g_alloca (sizeof (memchunks[0]) * prime_size); + memset (memchunks, 0, sizeof (memchunks[0]) * prime_size); + + ps = g_new (guint8*, number_of_blocks); + 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]); + g_free (ps); + g_free (ss); + + return NULL; +} + +static gpointer +test_sliced_mem_thread (gpointer data) +{ + guint32 rand_accu = 2147483563; + guint i, j; + guint8 **ps; + guint *ss; + + /* initialize random numbers */ + if (data) + rand_accu = *(guint32*) data; + else + { + GTimeVal rand_tv; + g_get_current_time (&rand_tv); + rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16); + } + + ps = g_new (guint8*, number_of_blocks); + 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] = g_slice_alloc (ss[i] + corruption()); + for (j = 0; j < number_of_repetitions; j++) + { + /* free number_of_blocks/2 blocks */ + for (i = 0; i < number_of_blocks; i += 2) + g_slice_free1 (ss[i] + corruption(), ps[i] + corruption()); + /* 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] + corruption()); + } + } + /* free number_of_blocks blocks */ + for (i = 0; i < number_of_blocks; i++) + g_slice_free1 (ss[i] + corruption(), ps[i] + corruption()); + /* 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] = g_slice_alloc (sz + corruption()); + for (j = 0; j < k; j++) + g_slice_free1 (sz + corruption(), ps[j] + corruption()); + } + g_free (ps); + g_free (ss); + + return NULL; +} + +static void +usage (void) +{ + g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c][~] [maxblocksize] [seed]\n"); +} + +int +main (int argc, + char *argv[]) +{ + guint seed32, *seedp = NULL; + gboolean ccounters = FALSE, use_memchunks = FALSE; + guint n_threads = 1; + const gchar *mode = "slab allocator + magazine cache", *emode = " "; +#ifdef __SYMBIAN32__ + g_log_set_handler (NULL, G_LOG_FLAG_FATAL| G_LOG_FLAG_RECURSION | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG, &mrtLogHandler, NULL); + g_set_print_handler(mrtPrintHandler); + #endif /*__SYMBIAN32__*/ + if (argc > 1) + n_threads = g_ascii_strtoull (argv[1], NULL, 10); + if (argc > 2) + { + guint i, l = strlen (argv[2]); + for (i = 0; i < l; i++) + switch (argv[2][i]) + { + case 'G': /* GLib mode */ + g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, FALSE); + g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES, FALSE); + mode = "slab allocator + magazine cache"; + break; + case 'S': /* slab mode */ + g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, FALSE); + g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES, TRUE); + mode = "slab allocator"; + break; + case 'M': /* malloc mode */ + 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_WORKING_SET_MSECS, 0); + clean_memchunks = TRUE; + emode = " with eager freeing"; + break; + case 'c': /* print contention counters */ + ccounters = TRUE; + break; + case '~': + want_corruption = TRUE; /* force occasional corruption */ + break; + default: + usage(); + return 1; + } + } + if (argc > 3) + prime_size = g_ascii_strtoull (argv[3], NULL, 10); + if (argc > 4) + { + seed32 = g_ascii_strtoull (argv[4], NULL, 10); + seedp = &seed32; + } + + g_thread_init (NULL); + + if (argc <= 1) + usage(); + + { + gchar strseed[64] = ""; + GThread **threads; + guint i; + + if (seedp) + g_snprintf (strseed, 64, "%u", *seedp); + g_print ("Starting %d threads allocating random blocks <= %u bytes with seed=%s using %s%s\n", n_threads, prime_size, strseed, mode, emode); + threads = (GThread **)g_alloca (sizeof(GThread*) * n_threads); + 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]); + + if (ccounters) + { + guint n, n_chunks = g_slice_get_config (G_SLICE_CONFIG_CHUNK_SIZES); + g_print (" ChunkSize | MagazineSize | Contention\n"); + for (i = 0; i < n_chunks; i++) + { + gint64 *vals = g_slice_get_config_state (G_SLICE_CONFIG_CONTENTION_COUNTER, i, &n); + g_print (" %9llu | %9llu | %9llu\n", vals[0], vals[2], vals[1]); + g_free (vals); + } + } + else + g_print ("Done.\n"); +#ifdef __SYMBIAN32__ + testResultXml("slice-test"); + #endif /* EMULATOR */ + return 0; + } +}