00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "config.h"
00024 #include "system.h"
00025 #include "alloc-pool.h"
00026 #include "hashtab.h"
00027
00028 #define align_eight(x) (((x+7) >> 3) << 3)
00029
00030
00031 typedef struct allocation_object_def
00032 {
00033 #ifdef ENABLE_CHECKING
00034
00035 ALLOC_POOL_ID_TYPE id;
00036 #endif
00037
00038 union
00039 {
00040
00041 char data[1];
00042
00043
00044
00045
00046 char *align_p;
00047 HOST_WIDEST_INT align_i;
00048 long double align_ld;
00049 } u;
00050 } allocation_object;
00051
00052
00053 #define ALLOCATION_OBJECT_PTR_FROM_USER_PTR(X) \
00054 ((allocation_object *) (((char *) (X)) \
00055 - offsetof (allocation_object, u.data)))
00056
00057
00058 #define USER_PTR_FROM_ALLOCATION_OBJECT_PTR(X) \
00059 ((void *) (((allocation_object *) (X))->u.data))
00060
00061 #ifdef ENABLE_CHECKING
00062
00063 static ALLOC_POOL_ID_TYPE last_id;
00064 #endif
00065
00066 #ifdef GATHER_STATISTICS
00067
00068
00069 struct alloc_pool_descriptor
00070 {
00071 const char *name;
00072 int allocated;
00073 int created;
00074 int peak;
00075 int current;
00076 };
00077
00078
00079 static htab_t alloc_pool_hash;
00080
00081
00082 static hashval_t
00083 hash_descriptor (const void *p)
00084 {
00085 const struct alloc_pool_descriptor *d = p;
00086 return htab_hash_pointer (d->name);
00087 }
00088 static int
00089 eq_descriptor (const void *p1, const void *p2)
00090 {
00091 const struct alloc_pool_descriptor *d = p1;
00092 return d->name == p2;
00093 }
00094
00095
00096 static struct alloc_pool_descriptor *
00097 alloc_pool_descriptor (const char *name)
00098 {
00099 struct alloc_pool_descriptor **slot;
00100
00101 if (!alloc_pool_hash)
00102 alloc_pool_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
00103
00104 slot = (struct alloc_pool_descriptor **)
00105 htab_find_slot_with_hash (alloc_pool_hash, name,
00106 htab_hash_pointer (name),
00107 1);
00108 if (*slot)
00109 return *slot;
00110 *slot = xcalloc (sizeof (**slot), 1);
00111 (*slot)->name = name;
00112 return *slot;
00113 }
00114 #endif
00115
00116
00117
00118
00119 alloc_pool
00120 create_alloc_pool (const char *name, size_t size, size_t num)
00121 {
00122 alloc_pool pool;
00123 size_t pool_size, header_size;
00124 #ifdef GATHER_STATISTICS
00125 struct alloc_pool_descriptor *desc;
00126 #endif
00127
00128 gcc_assert (name);
00129
00130
00131 if (size < sizeof (alloc_pool_list))
00132 size = sizeof (alloc_pool_list);
00133
00134
00135 size = align_eight (size);
00136
00137 #ifdef ENABLE_CHECKING
00138
00139 size += offsetof (allocation_object, u.data);
00140 #endif
00141
00142
00143 gcc_assert (num);
00144
00145
00146 pool_size = sizeof (struct alloc_pool_def);
00147
00148
00149 pool = xmalloc (pool_size);
00150
00151
00152 pool->name = name;
00153 #ifdef GATHER_STATISTICS
00154 desc = alloc_pool_descriptor (name);
00155 desc->created++;
00156 #endif
00157 pool->elt_size = size;
00158 pool->elts_per_block = num;
00159
00160
00161 header_size = align_eight (sizeof (struct alloc_pool_list_def));
00162
00163 pool->block_size = (size * num) + header_size;
00164 pool->free_list = NULL;
00165 pool->elts_allocated = 0;
00166 pool->elts_free = 0;
00167 pool->blocks_allocated = 0;
00168 pool->block_list = NULL;
00169
00170 #ifdef ENABLE_CHECKING
00171
00172
00173 last_id++;
00174 if (last_id == 0)
00175 last_id++;
00176
00177 pool->id = last_id;
00178 #endif
00179
00180 return (pool);
00181 }
00182
00183
00184 void
00185 free_alloc_pool (alloc_pool pool)
00186 {
00187 alloc_pool_list block, next_block;
00188 #ifdef GATHER_STATISTICS
00189 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
00190 #endif
00191
00192 gcc_assert (pool);
00193
00194
00195 for (block = pool->block_list; block != NULL; block = next_block)
00196 {
00197 next_block = block->next;
00198 free (block);
00199 #ifdef GATHER_STATISTICS
00200 desc->current -= pool->block_size;
00201 #endif
00202 }
00203 #ifdef ENABLE_CHECKING
00204 memset (pool, 0xaf, sizeof (*pool));
00205 #endif
00206
00207 free (pool);
00208 }
00209
00210
00211 void
00212 free_alloc_pool_if_empty (alloc_pool *pool)
00213 {
00214 if ((*pool)->elts_free == (*pool)->elts_allocated)
00215 {
00216 free_alloc_pool (*pool);
00217 *pool = NULL;
00218 }
00219 }
00220
00221
00222 void *
00223 pool_alloc (alloc_pool pool)
00224 {
00225 alloc_pool_list header;
00226 char *block;
00227 #ifdef GATHER_STATISTICS
00228 struct alloc_pool_descriptor *desc = alloc_pool_descriptor (pool->name);
00229
00230 desc->allocated+=pool->elt_size;
00231 #endif
00232
00233 gcc_assert (pool);
00234
00235
00236 if (!pool->free_list)
00237 {
00238 size_t i;
00239 alloc_pool_list block_header;
00240
00241
00242 block = XNEWVEC (char, pool->block_size);
00243 block_header = (alloc_pool_list) block;
00244 block += align_eight (sizeof (struct alloc_pool_list_def));
00245 #ifdef GATHER_STATISTICS
00246 desc->current += pool->block_size;
00247 if (desc->peak < desc->current)
00248 desc->peak = desc->current;
00249 #endif
00250
00251
00252 block_header->next = pool->block_list;
00253 pool->block_list = block_header;
00254
00255
00256 for (i = 0; i < pool->elts_per_block; i++, block += pool->elt_size)
00257 {
00258 #ifdef ENABLE_CHECKING
00259
00260 ((allocation_object *) block)->id = 0;
00261 #endif
00262 header = (alloc_pool_list) USER_PTR_FROM_ALLOCATION_OBJECT_PTR (block);
00263 header->next = pool->free_list;
00264 pool->free_list = header;
00265 }
00266
00267
00268 pool->elts_allocated += pool->elts_per_block;
00269 pool->elts_free += pool->elts_per_block;
00270 pool->blocks_allocated += 1;
00271 }
00272
00273
00274 header = pool->free_list;
00275 pool->free_list = header->next;
00276 pool->elts_free--;
00277
00278 #ifdef ENABLE_CHECKING
00279
00280 ALLOCATION_OBJECT_PTR_FROM_USER_PTR (header)->id = pool->id;
00281 #endif
00282
00283 return ((void *) header);
00284 }
00285
00286
00287 void
00288 pool_free (alloc_pool pool, void *ptr)
00289 {
00290 alloc_pool_list header;
00291
00292 gcc_assert (ptr);
00293
00294 #ifdef ENABLE_CHECKING
00295 memset (ptr, 0xaf, pool->elt_size - offsetof (allocation_object, u.data));
00296
00297
00298 gcc_assert (pool->id == ALLOCATION_OBJECT_PTR_FROM_USER_PTR (ptr)->id);
00299
00300
00301 ALLOCATION_OBJECT_PTR_FROM_USER_PTR (ptr)->id = 0;
00302 #else
00303
00304 gcc_assert (pool->elts_free < pool->elts_allocated);
00305 #endif
00306
00307 header = (alloc_pool_list) ptr;
00308 header->next = pool->free_list;
00309 pool->free_list = header;
00310 pool->elts_free++;
00311 }
00312
00313 #ifdef GATHER_STATISTICS
00314
00315
00316 struct output_info
00317 {
00318 int count;
00319 int size;
00320 };
00321
00322
00323
00324 static int
00325 print_statistics (void **slot, void *b)
00326 {
00327 struct alloc_pool_descriptor *d = (struct alloc_pool_descriptor *) *slot;
00328 struct output_info *i = (struct output_info *) b;
00329
00330 if (d->allocated)
00331 {
00332 fprintf (stderr, "%-21s %6d %10d %10d %10d\n", d->name,
00333 d->created, d->allocated, d->peak, d->current);
00334 i->size += d->allocated;
00335 i->count += d->created;
00336 }
00337 return 1;
00338 }
00339 #endif
00340
00341
00342 void
00343 dump_alloc_pool_statistics (void)
00344 {
00345 #ifdef GATHER_STATISTICS
00346 struct output_info info;
00347
00348 if (!alloc_pool_hash)
00349 return;
00350
00351 fprintf (stderr, "\nAlloc-pool Kind Pools Allocated Peak Leak\n");
00352 fprintf (stderr, "-------------------------------------------------------------\n");
00353 info.count = 0;
00354 info.size = 0;
00355 htab_traverse (alloc_pool_hash, print_statistics, &info);
00356 fprintf (stderr, "-------------------------------------------------------------\n");
00357 fprintf (stderr, "%-20s %7d %10d\n",
00358 "Total", info.count, info.size);
00359 fprintf (stderr, "-------------------------------------------------------------\n");
00360 #endif
00361 }