nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* GLIB sliced memory - fast threaded memory chunk allocator |
2 | * Copyright (C) 2005 Tim Janik |
||
3 | * |
||
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. |
||
8 | * |
||
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. |
||
13 | * |
||
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/>. |
||
16 | */ |
||
17 | #include <glib.h> |
||
18 | |||
19 | #include <stdio.h> |
||
20 | #include <string.h> |
||
21 | |||
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; |
||
28 | |||
29 | /* --- old memchunk prototypes (memchunks.c) --- */ |
||
30 | GMemChunk* old_mem_chunk_new (const gchar *name, |
||
31 | gint atom_size, |
||
32 | gulong area_size, |
||
33 | gint type); |
||
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, |
||
38 | gpointer mem); |
||
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 |
||
45 | #endif |
||
46 | |||
47 | /* --- functions --- */ |
||
48 | static inline int |
||
49 | corruption (void) |
||
50 | { |
||
51 | if (G_UNLIKELY (want_corruption)) |
||
52 | { |
||
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; |
||
56 | } |
||
57 | return 0; |
||
58 | } |
||
59 | |||
60 | static inline gpointer |
||
61 | memchunk_alloc (GMemChunk **memchunkp, |
||
62 | guint size) |
||
63 | { |
||
64 | size = MAX (size, 1); |
||
65 | if (G_UNLIKELY (!*memchunkp)) |
||
66 | *memchunkp = old_mem_chunk_new ("", size, 4096, G_ALLOC_AND_FREE); |
||
67 | return old_mem_chunk_alloc (*memchunkp); |
||
68 | } |
||
69 | |||
70 | static inline void |
||
71 | memchunk_free (GMemChunk *memchunk, |
||
72 | gpointer chunk) |
||
73 | { |
||
74 | old_mem_chunk_free (memchunk, chunk); |
||
75 | if (clean_memchunks) |
||
76 | old_mem_chunk_clean (memchunk); |
||
77 | } |
||
78 | |||
79 | static gpointer |
||
80 | test_memchunk_thread (gpointer data) |
||
81 | { |
||
82 | GMemChunk **memchunks; |
||
83 | guint i, j; |
||
84 | guint8 **ps; |
||
85 | guint *ss; |
||
86 | guint32 rand_accu = 2147483563; |
||
87 | /* initialize random numbers */ |
||
88 | if (data) |
||
89 | rand_accu = *(guint32*) data; |
||
90 | else |
||
91 | { |
||
92 | GTimeVal rand_tv; |
||
93 | g_get_current_time (&rand_tv); |
||
94 | rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16); |
||
95 | } |
||
96 | |||
97 | /* prepare for memchunk creation */ |
||
98 | memchunks = g_alloca (sizeof (memchunks[0]) * prime_size); |
||
99 | memset (memchunks, 0, sizeof (memchunks[0]) * prime_size); |
||
100 | |||
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++) |
||
110 | { |
||
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) |
||
116 | { |
||
117 | ss[i] = quick_rand32() % prime_size; |
||
118 | ps[i] = memchunk_alloc (&memchunks[ss[i]], ss[i]); |
||
119 | } |
||
120 | } |
||
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++) |
||
126 | { |
||
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]); |
||
133 | } |
||
134 | /* cleanout memchunks */ |
||
135 | for (i = 0; i < prime_size; i++) |
||
136 | if (memchunks[i]) |
||
137 | old_mem_chunk_destroy (memchunks[i]); |
||
138 | g_free (ps); |
||
139 | g_free (ss); |
||
140 | |||
141 | return NULL; |
||
142 | } |
||
143 | |||
144 | static gpointer |
||
145 | test_sliced_mem_thread (gpointer data) |
||
146 | { |
||
147 | guint32 rand_accu = 2147483563; |
||
148 | guint i, j; |
||
149 | guint8 **ps; |
||
150 | guint *ss; |
||
151 | |||
152 | /* initialize random numbers */ |
||
153 | if (data) |
||
154 | rand_accu = *(guint32*) data; |
||
155 | else |
||
156 | { |
||
157 | GTimeVal rand_tv; |
||
158 | g_get_current_time (&rand_tv); |
||
159 | rand_accu = rand_tv.tv_usec + (rand_tv.tv_sec << 16); |
||
160 | } |
||
161 | |||
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++) |
||
171 | { |
||
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) |
||
177 | { |
||
178 | ss[i] = quick_rand32() % prime_size; |
||
179 | ps[i] = g_slice_alloc (ss[i] + corruption()); |
||
180 | } |
||
181 | } |
||
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++) |
||
187 | { |
||
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()); |
||
194 | } |
||
195 | g_free (ps); |
||
196 | g_free (ss); |
||
197 | |||
198 | return NULL; |
||
199 | } |
||
200 | |||
201 | static void |
||
202 | usage (void) |
||
203 | { |
||
204 | g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c][~] [maxblocksize] [seed]\n"); |
||
205 | } |
||
206 | |||
207 | int |
||
208 | main (int argc, |
||
209 | char *argv[]) |
||
210 | { |
||
211 | guint seed32, *seedp = NULL; |
||
212 | gboolean ccounters = FALSE, use_memchunks = FALSE; |
||
213 | guint n_threads = 1; |
||
214 | const gchar *mode = "slab allocator + magazine cache", *emode = " "; |
||
215 | if (argc > 1) |
||
216 | n_threads = g_ascii_strtoull (argv[1], NULL, 10); |
||
217 | if (argc > 2) |
||
218 | { |
||
219 | guint i, l = strlen (argv[2]); |
||
220 | for (i = 0; i < l; i++) |
||
221 | switch (argv[2][i]) |
||
222 | { |
||
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"; |
||
227 | break; |
||
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"; |
||
232 | break; |
||
233 | case 'M': /* malloc mode */ |
||
234 | g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC, TRUE); |
||
235 | mode = "system malloc"; |
||
236 | break; |
||
237 | case 'O': /* old memchunks */ |
||
238 | use_memchunks = TRUE; |
||
239 | mode = "old memchunks"; |
||
240 | break; |
||
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"; |
||
245 | break; |
||
246 | case 'c': /* print contention counters */ |
||
247 | ccounters = TRUE; |
||
248 | break; |
||
249 | case '~': |
||
250 | want_corruption = TRUE; /* force occasional corruption */ |
||
251 | break; |
||
252 | default: |
||
253 | usage(); |
||
254 | return 1; |
||
255 | } |
||
256 | } |
||
257 | if (argc > 3) |
||
258 | prime_size = g_ascii_strtoull (argv[3], NULL, 10); |
||
259 | if (argc > 4) |
||
260 | { |
||
261 | seed32 = g_ascii_strtoull (argv[4], NULL, 10); |
||
262 | seedp = &seed32; |
||
263 | } |
||
264 | |||
265 | if (argc <= 1) |
||
266 | usage(); |
||
267 | |||
268 | { |
||
269 | gchar strseed[64] = "<random>"; |
||
270 | GThread **threads; |
||
271 | guint i; |
||
272 | |||
273 | if (seedp) |
||
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); |
||
276 | |||
277 | threads = g_alloca (sizeof(GThread*) * n_threads); |
||
278 | if (!use_memchunks) |
||
279 | for (i = 0; i < n_threads; i++) |
||
280 | threads[i] = g_thread_create (test_sliced_mem_thread, seedp, TRUE, NULL); |
||
281 | else |
||
282 | { |
||
283 | for (i = 0; i < n_threads; i++) |
||
284 | threads[i] = g_thread_create (test_memchunk_thread, seedp, TRUE, NULL); |
||
285 | } |
||
286 | for (i = 0; i < n_threads; i++) |
||
287 | g_thread_join (threads[i]); |
||
288 | |||
289 | if (ccounters) |
||
290 | { |
||
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++) |
||
294 | { |
||
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]); |
||
297 | g_free (vals); |
||
298 | } |
||
299 | } |
||
300 | else |
||
301 | g_print ("Done.\n"); |
||
302 | return 0; |
||
303 | } |
||
304 | } |