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 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.
24 #define quick_rand32() (rand_accu = 1664525 * rand_accu + 1013904223, rand_accu)
25 static guint prime_size
= 1021; // 769; // 509
26 static gboolean clean_memchunks
= FALSE
;
27 static guint number_of_blocks
= 10000; /* total number of blocks allocated */
28 static guint number_of_repetitions
= 10000; /* number of alloc+free repetitions */
30 /* --- old memchunk prototypes (memchunks.c) --- */
31 void old_mem_chunks_init (void);
32 GMemChunk
* old_mem_chunk_new (const gchar
*name
,
36 void old_mem_chunk_destroy (GMemChunk
*mem_chunk
);
37 gpointer
old_mem_chunk_alloc (GMemChunk
*mem_chunk
);
38 gpointer
old_mem_chunk_alloc0 (GMemChunk
*mem_chunk
);
39 void old_mem_chunk_free (GMemChunk
*mem_chunk
,
41 void old_mem_chunk_clean (GMemChunk
*mem_chunk
);
42 void old_mem_chunk_reset (GMemChunk
*mem_chunk
);
43 void old_mem_chunk_print (GMemChunk
*mem_chunk
);
44 void old_mem_chunk_info (void);
45 #ifndef G_ALLOC_AND_FREE
46 #define G_ALLOC_AND_FREE 2
49 /* --- functions --- */
50 static inline gpointer
51 memchunk_alloc (GMemChunk
**memchunkp
,
55 if (G_UNLIKELY (!*memchunkp
))
56 *memchunkp
= old_mem_chunk_new ("", size
, 4096, G_ALLOC_AND_FREE
);
57 return old_mem_chunk_alloc (*memchunkp
);
61 memchunk_free (GMemChunk
*memchunk
,
64 old_mem_chunk_free (memchunk
, chunk
);
66 old_mem_chunk_clean (memchunk
);
70 test_memchunk_thread (gpointer data
)
72 GMemChunk
**memchunks
;
76 guint32 rand_accu
= 2147483563;
77 /* initialize random numbers */
79 rand_accu
= *(guint32
*) data
;
83 g_get_current_time (&rand_tv
);
84 rand_accu
= rand_tv
.tv_usec
+ (rand_tv
.tv_sec
<< 16);
87 /* prepare for memchunk creation */
88 memchunks
= g_alloca (sizeof (memchunks
[0]) * prime_size
);
89 memset (memchunks
, 0, sizeof (memchunks
[0]) * prime_size
);
91 ps
= g_new (guint8
*, number_of_blocks
);
92 ss
= g_new (guint
, number_of_blocks
);
93 /* create number_of_blocks random sizes */
94 for (i
= 0; i
< number_of_blocks
; i
++)
95 ss
[i
] = quick_rand32() % prime_size
;
96 /* allocate number_of_blocks blocks */
97 for (i
= 0; i
< number_of_blocks
; i
++)
98 ps
[i
] = memchunk_alloc (&memchunks
[ss
[i
]], ss
[i
]);
99 for (j
= 0; j
< number_of_repetitions
; j
++)
101 /* free number_of_blocks/2 blocks */
102 for (i
= 0; i
< number_of_blocks
; i
+= 2)
103 memchunk_free (memchunks
[ss
[i
]], ps
[i
]);
104 /* allocate number_of_blocks/2 blocks with new sizes */
105 for (i
= 0; i
< number_of_blocks
; i
+= 2)
107 ss
[i
] = quick_rand32() % prime_size
;
108 ps
[i
] = memchunk_alloc (&memchunks
[ss
[i
]], ss
[i
]);
111 /* free number_of_blocks blocks */
112 for (i
= 0; i
< number_of_blocks
; i
++)
113 memchunk_free (memchunks
[ss
[i
]], ps
[i
]);
114 /* alloc and free many equally sized chunks in a row */
115 for (i
= 0; i
< number_of_repetitions
; i
++)
117 guint sz
= quick_rand32() % prime_size
;
118 guint k
= number_of_blocks
/ 100;
119 for (j
= 0; j
< k
; j
++)
120 ps
[j
] = memchunk_alloc (&memchunks
[sz
], sz
);
121 for (j
= 0; j
< k
; j
++)
122 memchunk_free (memchunks
[sz
], ps
[j
]);
124 /* cleanout memchunks */
125 for (i
= 0; i
< prime_size
; i
++)
127 old_mem_chunk_destroy (memchunks
[i
]);
135 test_sliced_mem_thread (gpointer data
)
137 guint32 rand_accu
= 2147483563;
138 /* initialize random numbers */
140 rand_accu
= *(guint32
*) data
;
144 g_get_current_time (&rand_tv
);
145 rand_accu
= rand_tv
.tv_usec
+ (rand_tv
.tv_sec
<< 16);
149 guint8
**ps
= g_new (guint8
*, number_of_blocks
);
150 guint
*ss
= g_new (guint
, number_of_blocks
);
151 /* create number_of_blocks random sizes */
152 for (i
= 0; i
< number_of_blocks
; i
++)
153 ss
[i
] = quick_rand32() % prime_size
;
154 /* allocate number_of_blocks blocks */
155 for (i
= 0; i
< number_of_blocks
; i
++)
156 ps
[i
] = g_slice_alloc (ss
[i
]);
157 for (j
= 0; j
< number_of_repetitions
; j
++)
159 /* free number_of_blocks/2 blocks */
160 for (i
= 0; i
< number_of_blocks
; i
+= 2)
161 g_slice_free1 (ss
[i
], ps
[i
]);
162 /* allocate number_of_blocks/2 blocks with new sizes */
163 for (i
= 0; i
< number_of_blocks
; i
+= 2)
165 ss
[i
] = quick_rand32() % prime_size
;
166 ps
[i
] = g_slice_alloc (ss
[i
]);
169 /* free number_of_blocks blocks */
170 for (i
= 0; i
< number_of_blocks
; i
++)
171 g_slice_free1 (ss
[i
], ps
[i
]);
172 /* alloc and free many equally sized chunks in a row */
173 for (i
= 0; i
< number_of_repetitions
; i
++)
175 guint sz
= quick_rand32() % prime_size
;
176 guint k
= number_of_blocks
/ 100;
177 for (j
= 0; j
< k
; j
++)
178 ps
[j
] = g_slice_alloc (sz
);
179 for (j
= 0; j
< k
; j
++)
180 g_slice_free1 (sz
, ps
[j
]);
191 g_print ("Usage: slice-test [n_threads] [G|S|M|O][f][c] [maxblocksize] [seed]\n");
198 guint seed32
, *seedp
= NULL
;
199 gboolean ccounters
= FALSE
, use_memchunks
= FALSE
;
201 const gchar
*mode
= "slab allocator + magazine cache", *emode
= " ";
203 n_threads
= g_ascii_strtoull (argv
[1], NULL
, 10);
206 guint i
, l
= strlen (argv
[2]);
207 for (i
= 0; i
< l
; i
++)
210 case 'G': /* GLib mode */
211 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC
, FALSE
);
212 g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES
, FALSE
);
213 mode
= "slab allocator + magazine cache";
215 case 'S': /* slab mode */
216 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC
, FALSE
);
217 g_slice_set_config (G_SLICE_CONFIG_BYPASS_MAGAZINES
, TRUE
);
218 mode
= "slab allocator";
220 case 'M': /* malloc mode */
221 g_slice_set_config (G_SLICE_CONFIG_ALWAYS_MALLOC
, TRUE
);
222 mode
= "system malloc";
224 case 'O': /* old memchunks */
225 use_memchunks
= TRUE
;
226 mode
= "old memchunks";
228 case 'f': /* eager freeing */
229 g_slice_set_config (G_SLICE_CONFIG_WORKING_SET_MSECS
, 0);
230 clean_memchunks
= TRUE
;
231 emode
= " with eager freeing";
233 case 'c': /* print contention counters */
242 prime_size
= g_ascii_strtoull (argv
[3], NULL
, 10);
245 seed32
= g_ascii_strtoull (argv
[4], NULL
, 10);
249 g_thread_init (NULL
);
254 gchar strseed
[64] = "<random>";
256 g_snprintf (strseed
, 64, "%u", *seedp
);
257 g_print ("Starting %d threads allocating random blocks <= %u bytes with seed=%s using %s%s\n", n_threads
, prime_size
, strseed
, mode
, emode
);
259 GThread
*threads
[n_threads
];
262 for (i
= 0; i
< n_threads
; i
++)
263 threads
[i
] = g_thread_create_full (test_sliced_mem_thread
, seedp
, 0, TRUE
, FALSE
, 0, NULL
);
266 old_mem_chunks_init();
267 for (i
= 0; i
< n_threads
; i
++)
268 threads
[i
] = g_thread_create_full (test_memchunk_thread
, seedp
, 0, TRUE
, FALSE
, 0, NULL
);
270 for (i
= 0; i
< n_threads
; i
++)
271 g_thread_join (threads
[i
]);
275 guint n
, n_chunks
= g_slice_get_config (G_SLICE_CONFIG_CHUNK_SIZES
);
276 g_print (" ChunkSize | MagazineSize | Contention\n");
277 for (i
= 0; i
< n_chunks
; i
++)
279 gint64
*vals
= g_slice_get_config_state (G_SLICE_CONFIG_CONTENTION_COUNTER
, i
, &n
);
280 g_print (" %9llu | %9llu | %9llu\n", vals
[0], vals
[2], vals
[1]);