1 /* GLIB sliced memory - fast threaded memory chunk allocator
2 * Copyright (C) 2005 Tim Janik
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.1 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, see <http://www.gnu.org/licenses/>.
22 #define quick_rand32() (rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
23 static guint prime_size
= 1021; /* 769; 509 */
24 static gboolean clean_memchunks
= FALSE
;
25 static guint number_of_blocks
= 10000; /* total number of blocks allocated */
26 static guint number_of_repetitions
= 10000; /* number of alloc+free repetitions */
27 static gboolean want_corruption
= FALSE
;
29 /* --- old memchunk prototypes (memchunks.c) --- */
30 GMemChunk
* old_mem_chunk_new (const gchar
*name
,
34 void old_mem_chunk_destroy (GMemChunk
*mem_chunk
);
35 gpointer
old_mem_chunk_alloc (GMemChunk
*mem_chunk
);
36 gpointer
old_mem_chunk_alloc0 (GMemChunk
*mem_chunk
);
37 void old_mem_chunk_free (GMemChunk
*mem_chunk
,
39 void old_mem_chunk_clean (GMemChunk
*mem_chunk
);
40 void old_mem_chunk_reset (GMemChunk
*mem_chunk
);
41 void old_mem_chunk_print (GMemChunk
*mem_chunk
);
42 void old_mem_chunk_info (void);
43 #ifndef G_ALLOC_AND_FREE
44 #define G_ALLOC_AND_FREE 2
47 /* --- functions --- */
51 if (G_UNLIKELY (want_corruption
))
53 /* corruption per call likelyness is about 1:4000000 */
54 guint32 r
= g_random_int() % 8000009;
55 return r
== 277 ? +1 : r
== 281 ? -1 : 0;
60 static inline gpointer
61 memchunk_alloc (GMemChunk
**memchunkp
,
65 if (G_UNLIKELY (!*memchunkp
))
66 *memchunkp
= old_mem_chunk_new ("", size
, 4096, G_ALLOC_AND_FREE
);
67 return old_mem_chunk_alloc (*memchunkp
);
71 memchunk_free (GMemChunk
*memchunk
,
74 old_mem_chunk_free (memchunk
, chunk
);
76 old_mem_chunk_clean (memchunk
);
80 test_memchunk_thread (gpointer data
)
82 GMemChunk
**memchunks
;
86 guint32 rand_accu
= 2147483563;
87 /* initialize random numbers */
89 rand_accu
= *(guint32
*) data
;
93 g_get_current_time (&rand_tv
);
94 rand_accu
= rand_tv
.tv_usec
+ (rand_tv
.tv_sec
<< 16);
97 /* prepare for memchunk creation */
98 memchunks
= g_alloca (sizeof (memchunks
[0]) * prime_size
);
99 memset (memchunks
, 0, sizeof (memchunks
[0]) * prime_size
);
101 ps
= g_new (guint8
*, number_of_blocks
);
102 ss
= g_new (guint
, number_of_blocks
);
103 /* create number_of_blocks random sizes */
104 for (i
= 0; i
< number_of_blocks
; i
++)
105 ss
[i
] = quick_rand32() % prime_size
;
106 /* allocate number_of_blocks blocks */
107 for (i
= 0; i
< number_of_blocks
; i
++)
108 ps
[i
] = memchunk_alloc (&memchunks
[ss
[i
]], ss
[i
]);
109 for (j
= 0; j
< number_of_repetitions
; j
++)
111 /* free number_of_blocks/2 blocks */
112 for (i
= 0; i
< number_of_blocks
; i
+= 2)
113 memchunk_free (memchunks
[ss
[i
]], ps
[i
]);
114 /* allocate number_of_blocks/2 blocks with new sizes */
115 for (i
= 0; i
< number_of_blocks
; i
+= 2)
117 ss
[i
] = quick_rand32() % prime_size
;
118 ps
[i
] = memchunk_alloc (&memchunks
[ss
[i
]], ss
[i
]);
121 /* free number_of_blocks blocks */
122 for (i
= 0; i
< number_of_blocks
; i
++)
123 memchunk_free (memchunks
[ss
[i
]], ps
[i
]);
124 /* alloc and free many equally sized chunks in a row */
125 for (i
= 0; i
< number_of_repetitions
; i
++)
127 guint sz
= quick_rand32() % prime_size
;
128 guint k
= number_of_blocks
/ 100;
129 for (j
= 0; j
< k
; j
++)
130 ps
[j
] = memchunk_alloc (&memchunks
[sz
], sz
);
131 for (j
= 0; j
< k
; j
++)
132 memchunk_free (memchunks
[sz
], ps
[j
]);
134 /* cleanout memchunks */
135 for (i
= 0; i
< prime_size
; i
++)
137 old_mem_chunk_destroy (memchunks
[i
]);
145 test_sliced_mem_thread (gpointer data
)
147 guint32 rand_accu
= 2147483563;
152 /* initialize random numbers */
154 rand_accu
= *(guint32
*) data
;
158 g_get_current_time (&rand_tv
);
159 rand_accu
= rand_tv
.tv_usec
+ (rand_tv
.tv_sec
<< 16);
162 ps
= g_new (guint8
*, number_of_blocks
);
163 ss
= g_new (guint
, number_of_blocks
);
164 /* create number_of_blocks random sizes */
165 for (i
= 0; i
< number_of_blocks
; i
++)
166 ss
[i
] = quick_rand32() % prime_size
;
167 /* allocate number_of_blocks blocks */
168 for (i
= 0; i
< number_of_blocks
; i
++)
169 ps
[i
] = g_slice_alloc (ss
[i
] + corruption());
170 for (j
= 0; j
< number_of_repetitions
; j
++)
172 /* free number_of_blocks/2 blocks */
173 for (i
= 0; i
< number_of_blocks
; i
+= 2)
174 g_slice_free1 (ss
[i
] + corruption(), ps
[i
] + corruption());
175 /* allocate number_of_blocks/2 blocks with new sizes */
176 for (i
= 0; i
< number_of_blocks
; i
+= 2)
178 ss
[i
] = quick_rand32() % prime_size
;
179 ps
[i
] = g_slice_alloc (ss
[i
] + corruption());
182 /* free number_of_blocks blocks */
183 for (i
= 0; i
< number_of_blocks
; i
++)
184 g_slice_free1 (ss
[i
] + corruption(), ps
[i
] + corruption());
185 /* alloc and free many equally sized chunks in a row */
186 for (i
= 0; i
< number_of_repetitions
; i
++)
188 guint sz
= quick_rand32() % prime_size
;
189 guint k
= number_of_blocks
/ 100;
190 for (j
= 0; j
< k
; j
++)
191 ps
[j
] = g_slice_alloc (sz
+ corruption());
192 for (j
= 0; j
< k
; j
++)
193 g_slice_free1 (sz
+ corruption(), ps
[j
] + corruption());
204 g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c][~] [maxblocksize] [seed]\n");
211 guint seed32
, *seedp
= NULL
;
212 gboolean ccounters
= FALSE
, use_memchunks
= FALSE
;
214 const gchar
*mode
= "slab allocator + magazine cache", *emode
= " ";
216 n_threads
= g_ascii_strtoull (argv
[1], NULL
, 10);
219 guint i
, l
= strlen (argv
[2]);
220 for (i
= 0; i
< l
; i
++)
223 case 'G': /* GLib mode */
224 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC
, FALSE
);
225 g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES
, FALSE
);
226 mode
= "slab allocator + magazine cache";
228 case 'S': /* slab mode */
229 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC
, FALSE
);
230 g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES
, TRUE
);
231 mode
= "slab allocator";
233 case 'M': /* malloc mode */
234 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC
, TRUE
);
235 mode
= "system malloc";
237 case 'O': /* old memchunks */
238 use_memchunks
= TRUE
;
239 mode
= "old memchunks";
241 case 'f': /* eager freeing */
242 g_slice_set_config (G_SLICE_CONFIG_WORKING_SET_MSECS
, 0);
243 clean_memchunks
= TRUE
;
244 emode
= " with eager freeing";
246 case 'c': /* print contention counters */
250 want_corruption
= TRUE
; /* force occasional corruption */
258 prime_size
= g_ascii_strtoull (argv
[3], NULL
, 10);
261 seed32
= g_ascii_strtoull (argv
[4], NULL
, 10);
269 gchar strseed
[64] = "<random>";
274 g_snprintf (strseed
, 64, "%u", *seedp
);
275 g_print ("Starting %d threads allocating random blocks <= %u bytes with seed=%s using %s%s\n", n_threads
, prime_size
, strseed
, mode
, emode
);
277 threads
= g_alloca (sizeof(GThread
*) * n_threads
);
279 for (i
= 0; i
< n_threads
; i
++)
280 threads
[i
] = g_thread_create (test_sliced_mem_thread
, seedp
, TRUE
, NULL
);
283 for (i
= 0; i
< n_threads
; i
++)
284 threads
[i
] = g_thread_create (test_memchunk_thread
, seedp
, TRUE
, NULL
);
286 for (i
= 0; i
< n_threads
; i
++)
287 g_thread_join (threads
[i
]);
291 guint n
, n_chunks
= g_slice_get_config (G_SLICE_CONFIG_CHUNK_SIZES
);
292 g_print (" ChunkSize | MagazineSize | Contention\n");
293 for (i
= 0; i
< n_chunks
; i
++)
295 gint64
*vals
= g_slice_get_config_state (G_SLICE_CONFIG_CONTENTION_COUNTER
, i
, &n
);
296 g_print (" %9" G_GINT64_FORMAT
" | %9" G_GINT64_FORMAT
" | %9" G_GINT64_FORMAT
"\n", vals
[0], vals
[2], vals
[1]);