First public contribution.
1 /* GLIB sliced memory - fast threaded memory chunk allocator
2 * Copyright (C) 2005 Tim Janik
3 * Portion Copyright © 2008-09 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 #include <sys/time.h> // gettimeofday
26 #define quick_rand32() (rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
27 static guint prime_size = 1021; // 769; // 509
28 static gboolean clean_memchunks = FALSE;
29 static guint number_of_blocks = 10000; /* total number of blocks allocated */
30 static guint number_of_repetitions = 10000; /* number of alloc+free repetitions */
32 /* --- old memchunk prototypes (memchunks.c) --- */
33 void old_mem_chunks_init (void);
34 GMemChunk* old_mem_chunk_new (const gchar *name,
38 void old_mem_chunk_destroy (GMemChunk *mem_chunk);
39 gpointer old_mem_chunk_alloc (GMemChunk *mem_chunk);
40 gpointer old_mem_chunk_alloc0 (GMemChunk *mem_chunk);
41 void old_mem_chunk_free (GMemChunk *mem_chunk,
43 void old_mem_chunk_clean (GMemChunk *mem_chunk);
44 void old_mem_chunk_reset (GMemChunk *mem_chunk);
45 void old_mem_chunk_print (GMemChunk *mem_chunk);
46 void old_mem_chunk_info (void);
47 #ifndef G_ALLOC_AND_FREE
48 #define G_ALLOC_AND_FREE 2
51 /* --- functions --- */
52 static inline gpointer
53 memchunk_alloc (GMemChunk **memchunkp,
57 if (G_UNLIKELY (!*memchunkp))
58 *memchunkp = old_mem_chunk_new ("", size, 4096, G_ALLOC_AND_FREE);
59 return old_mem_chunk_alloc (*memchunkp);
63 memchunk_free (GMemChunk *memchunk,
66 old_mem_chunk_free (memchunk, chunk);
68 old_mem_chunk_clean (memchunk);
72 test_memchunk_thread (gpointer data)
74 GMemChunk **memchunks;
78 guint32 rand_accu = 2147483563;
79 /* initialize random numbers */
81 rand_accu = *(guint32*) data;
84 struct timeval rand_tv;
85 gettimeofday (&rand_tv, NULL);
86 rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
89 /* prepare for memchunk creation */
90 memchunks = g_alloca (sizeof (memchunks[0]) * prime_size);
91 memset (memchunks, 0, sizeof (memchunks[0]) * prime_size);
93 ps = g_new (guint8*, number_of_blocks);
94 ss = g_new (guint, number_of_blocks);
95 /* create number_of_blocks random sizes */
96 for (i = 0; i < number_of_blocks; i++)
97 ss[i] = quick_rand32() % prime_size;
98 /* allocate number_of_blocks blocks */
99 for (i = 0; i < number_of_blocks; i++)
100 ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]);
101 for (j = 0; j < number_of_repetitions; j++)
103 /* free number_of_blocks/2 blocks */
104 for (i = 0; i < number_of_blocks; i += 2)
105 memchunk_free (memchunks[ss[i]], ps[i]);
106 /* allocate number_of_blocks/2 blocks with new sizes */
107 for (i = 0; i < number_of_blocks; i += 2)
109 ss[i] = quick_rand32() % prime_size;
110 ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]);
113 /* free number_of_blocks blocks */
114 for (i = 0; i < number_of_blocks; i++)
115 memchunk_free (memchunks[ss[i]], ps[i]);
116 /* alloc and free many equally sized chunks in a row */
117 for (i = 0; i < number_of_repetitions; i++)
119 guint sz = quick_rand32() % prime_size;
120 guint k = number_of_blocks / 100;
121 for (j = 0; j < k; j++)
122 ps[j] = memchunk_alloc (&memchunks[sz], sz);
123 for (j = 0; j < k; j++)
124 memchunk_free (memchunks[sz], ps[j]);
126 /* cleanout memchunks */
127 for (i = 0; i < prime_size; i++)
129 old_mem_chunk_destroy (memchunks[i]);
137 test_sliced_mem_thread (gpointer data)
143 guint32 rand_accu = 2147483563;
144 /* initialize random numbers */
146 rand_accu = *(guint32*) data;
149 struct timeval rand_tv;
150 gettimeofday (&rand_tv, NULL);
151 rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16);
155 /* guint8*/ ps = g_new (guint8*, number_of_blocks);
156 /* guint*/ ss = g_new (guint, number_of_blocks);
157 /* create number_of_blocks random sizes */
158 for (i = 0; i < number_of_blocks; i++)
159 ss[i] = quick_rand32() % prime_size;
160 /* allocate number_of_blocks blocks */
161 for (i = 0; i < number_of_blocks; i++)
162 ps[i] = g_slice_alloc (ss[i]);
163 for (j = 0; j < number_of_repetitions; j++)
165 /* free number_of_blocks/2 blocks */
166 for (i = 0; i < number_of_blocks; i += 2)
167 g_slice_free1 (ss[i], ps[i]);
168 /* allocate number_of_blocks/2 blocks with new sizes */
169 for (i = 0; i < number_of_blocks; i += 2)
171 ss[i] = quick_rand32() % prime_size;
172 ps[i] = g_slice_alloc (ss[i]);
175 /* free number_of_blocks blocks */
176 for (i = 0; i < number_of_blocks; i++)
177 g_slice_free1 (ss[i], ps[i]);
178 /* alloc and free many equally sized chunks in a row */
179 for (i = 0; i < number_of_repetitions; i++)
181 guint sz = quick_rand32() % prime_size;
182 guint k = number_of_blocks / 100;
183 for (j = 0; j < k; j++)
184 ps[j] = g_slice_alloc (sz);
185 for (j = 0; j < k; j++)
186 g_slice_free1 (sz, ps[j]);
197 g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c] [maxblocksize] [seed]\n");
204 gchar strseed[64] = "<random>";
206 guint seed32, *seedp = NULL;
207 gboolean ccounters = FALSE, use_memchunks = FALSE;
211 const gchar *mode = "slab allocator + magazine cache", *emode = " ";
213 n_threads = g_ascii_strtoull (argv[1], NULL, 10);
216 guint i, l = strlen (argv[2]);
217 for (i = 0; i < l; i++)
220 case 'G': /* GLib mode */
221 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, FALSE);
222 g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES, FALSE);
223 mode = "slab allocator + magazine cache";
225 case 'S': /* slab mode */
226 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, FALSE);
227 g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES, TRUE);
228 mode = "slab allocator";
230 case 'M': /* malloc mode */
231 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE);
232 mode = "system malloc";
234 case 'O': /* old memchunks */
235 use_memchunks = TRUE;
236 mode = "old memchunks";
238 case 'f': /* eager freeing */
239 g_slice_set_config (G_SLICE_CONFIG_WORKING_SET_MSECS, 0);
240 clean_memchunks = TRUE;
241 emode = " with eager freeing";
243 case 'c': /* print contention counters */
252 prime_size = g_ascii_strtoull (argv[3], NULL, 10);
255 seed32 = g_ascii_strtoull (argv[4], NULL, 10);
259 g_thread_init (NULL);
264 // gchar strseed[64] = "<random>";
266 g_snprintf (strseed, 64, "%u", *seedp);
267 g_print ("Starting %d threads allocating random blocks <= %u bytes with seed=%s using %s%s\n", n_threads, prime_size, strseed, mode, emode);
269 // GThread *threads[n_threads];
272 for (i = 0; i < n_threads; i++)
273 threads[i] = g_thread_create_full (test_sliced_mem_thread, seedp, 0, TRUE, FALSE, 0, NULL);
276 old_mem_chunks_init();
277 for (i = 0; i < n_threads; i++)
278 threads[i] = g_thread_create_full (test_memchunk_thread, seedp, 0, TRUE, FALSE, 0, NULL);
280 for (i = 0; i < n_threads; i++)
281 g_thread_join (threads[i]);
285 guint n, n_chunks = g_slice_get_config (G_SLICE_CONFIG_CHUNK_SIZES);
286 g_print (" ChunkSize | MagazineSize | Contention\n");
287 for (i = 0; i < n_chunks; i++)
289 gint64 *vals = g_slice_get_config_state (G_SLICE_CONFIG_CONTENTION_COUNTER, i, &n);
290 g_print (" %9llu | %9llu | %9llu\n", vals[0], vals[2], vals[1]);