/[ascend]/trunk/ascend/general/pool.h
ViewVC logotype

Contents of /trunk/ascend/general/pool.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2018 - (show annotations) (download) (as text)
Wed Apr 29 03:38:10 2009 UTC (15 years ago) by jpye
File MIME type: text/x-chdr
File size: 16882 byte(s)
Fixed compile for new header file locations <ascend/compiler/xxx.h> etc.
1 /*
2 * Ascend Pooled Memory Manager
3 * by Benjamin Andrew Allan
4 * Created: 2/96
5 * Version: $Revision: 1.1 $
6 * Version control file: $RCSfile: pool.h,v $
7 * Date last modified: $Date: 1997/07/18 11:37:02 $
8 * Last modified by: $Author: mthomas $
9 *
10 * This file is part of the Ascend Language Interpreter.
11 *
12 * Copyright (C) 1996 Benjamin Andrew Allan
13 *
14 * The Ascend Language Interpreter is free software; you can redistribute
15 * it and/or modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * The Ascend Language Interpreter is distributed in hope that it will be
20 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with the program; if not, write to the Free Software Foundation,
26 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
27 * COPYING.
28 *
29 */
30
31 /** @file
32 * Ascend Pooled Memory Manager.
33 * <pre>
34 * Contents: Pool Memory module
35 *
36 * Authors: Benjamin Andrew Allan
37 *
38 * Dates: 05/95 - original version: utilities/mem.[ch]
39 * nearly generic element allocation routines.
40 * 02/96 - copied to compiler and swapped pool for mem in
41 * names. deleted all the Karl foo of mem.c.
42 * 03/96 - retuned some of the parameters for compiler.
43 *
44 * Description: This generic element memory manager is yet another
45 * implementation of a fixed byte size malloc system
46 * that is more efficient than most standard mallocs. This
47 * is possible because we make the fixed size assumption.
48 * The idea is clearly not original.
49 * For best results, you must understand your memory
50 * usage pattern and tune the pool_create_store() parameters
51 * accordingly.
52 *
53 * This has similar functionality to free_store.[ch] but
54 * is a rather more efficient implementation with a better
55 * interface. The mem_ implementation of this code
56 * remains in utilities/ because the solvers (which may
57 * also stand alone) need to be able to link without the
58 * compiler goop.
59 *
60 * Detailed Description:
61 *
62 * The following definitions provide a generic and reasonably efficient memory
63 * allocation system for situations where many many objects of the same size
64 * need to be "allocated and deallocated" rapidly and stored efficiently:
65 * that is to say when normal malloc is too slow and expensive.
66 * This scheme does not play reference count games. Instead any elements that
67 * have been created and then used and subsequently "freed" go on a list
68 * and are handed out again at the next opportunity. The list is run LIFO.
69 * The list is associated with the pool_store_t.
70 *
71 * There is one restriction on the elements: they will be a multiple of the
72 * size of a pointer, even if you specify otherwise. If this is too large,
73 * write your own allocator. Think about how your elements align. On many
74 * architectures doubles should only be stored at addresses that are
75 * multiples of 8 bytes.
76 * There is the implicit restriction on a store that it must contain
77 * no more than MAXINT elements. If this is too small, write your own
78 * allocator.
79 *
80 * Even More Details
81 *
82 * If you specify an element size that is not a nice multiple of your machine
83 * word length, you are *very* likely to get data alignment (bus) errors.
84 * E.g., if your element is not a convenient multiple of
85 * sizeof(double) in size, double data are likely to die.
86 *
87 * The allocation scheme looks like so:
88 * [struct pool_store_header | ]
89 * __________________|
90 * |
91 * V
92 * pool _____________________________________________________
93 * | b | b | b | b | b | b | b | b | b | b | b | b | b |
94 * -----------------------------------------------------
95 * where each b is a pointer to an array of size 'width' of elements.
96 *
97 * The size characteristics of this scheme are tunable at run time so that
98 * it can be scaled well when the number of elements and likely amount
99 * of expansion required are known.
100 *
101 * When #including pool.h, make sure these files are #included first:
102 * #include <stdio.h>
103 * #include "utilities/ascConfig.h"
104 * #include "compiler.h"
105 * </pre>
106 */
107
108 #ifndef ASC_POOL_H
109 #define ASC_POOL_H
110
111 #include <ascend/utilities/ascConfig.h>
112
113 typedef struct pool_store_header *pool_store_t;
114 /**<
115 * The token for this memory system. Internal details of the
116 * implementation are private. Do not dereference or free this
117 * pointer.
118 */
119
120 /**
121 * Memory pool statistics data structure.
122 * This is the reporting structure for a pool_store_header query.
123 */
124 struct pool_statistics {
125 double p_eff; /**< bytes in use / bytes allocated */
126 double p_recycle; /**< avg reuses per element */
127 int elt_total; /**< current elements existing in store*/
128 int elt_taken; /**< fresh elements handed out */
129 int elt_inuse; /**< elements the user currently has */
130 int elt_onlist; /**< elements awaiting reuse */
131 int elt_size; /**< bytes/element, as mem sees it */
132 int str_len; /**< length of active pool. */
133 int str_wid; /**< elements/pointer in pool. */
134 };
135
136 ASC_DLLSPEC void pool_get_stats(struct pool_statistics *p_stats,
137 pool_store_t ps);
138 /**<
139 * Get statistics about a pool store.
140 * Stuffs the user's interface structure, p_stats, with info
141 * derived from ps given.
142 * If pool_LIGHTENING (see below) is TRUE, no statistics
143 * except elt_total, elt_taken, elt_onlist, and elt_size are
144 * available.
145 *
146 * @param p_stats Pointer to a pool_statistics struct to receive
147 * the info. If p_stats is NULL, an error message
148 * is printed and the function returns.
149 * @param ps Pointer to the pool store to query.
150 */
151
152 ASC_DLLSPEC pool_store_t pool_create_store(int length,
153 int width,
154 size_t eltsize,
155 int deltalen,
156 int deltapool);
157 /**<
158 * Creates and returns a new pool store. The returned pool_store_t
159 * contains all the necessary accounting information, but in particular
160 * the eltsize is fixed at creation. All elements requested from ps
161 * will be pointers to eltsize bytes of memory.
162 * Returns NULL if a store of the requested length*width*eltsize
163 * cannot be initially allocated.<br><br>
164 *
165 * The user may request more than length*width elements from the store:
166 * this will cause it to grow. It will grow (internally) in chunks of
167 * deltalen*width elements. The pool vector above grows in chunks of
168 * deltapool, the extra pointers in it being NULL until needed.<br><br>
169 *
170 * @param length The initial number of width*eltsize blocks that the
171 * new pool store will contain. If length < 1, an error
172 * message is printed and NULL is returned.
173 *
174 * @param width Number of elements in each block.
175 * Width should (for some architectures) be such that
176 * width*eltsize = 2^n - 32 for some n fairly large
177 * (heuristic: n= 9..13). Widths that are too large may
178 * be prone to causing excess page faults, though the
179 * process cpu time reported by the clock() can be much
180 * better for extremely large sizes. If width < 1, an
181 * error message is printed and NULL is returned.<br><br>
182 * Widths that are too small will result in an excessive
183 * number of pool expansions, which may severely limit
184 * performance on some VM systems. See deltapool below
185 * about pool expansions.<br><br>
186 * If you know something about the page size of your
187 * architecture, fiddling with width may help you reduce
188 * your page fault or cache miss count in some uses.
189 *
190 * @param eltsize Element size maintained by the pool.
191 * For maximum efficiency, eltsize should be an integer
192 * multiple of sizeof(void *). If it is not, elts will be
193 * padded so that this is the case. This is to avoid
194 * pointer data misalignment. This restriction may or
195 * may not help avoid alignment problems with items inside
196 * the user's element structure.
197 *
198 * @param deltalen Number of additional pointers in the pool that will be
199 * allocated when more elements are needed than are
200 * available internally. deltalen must be at least 1 or
201 * creation of the new pool will fail.
202 *
203 * @param deltapool Size change of the pool array when expanded. It should
204 * be as large as you are willing to tolerate. The pool
205 * array starts out completely filled (all pointers allocated).
206 * When the pool needs more pointers it gets them in chunks of
207 * at least deltapool. These additional pointers will not
208 * automatically have elements allocated to them; rather,
209 * they will be initialized to NULL and filled in only as the
210 * chunks of deltalen*width elements are required.
211
212 * @return A pointer to the newly created pool store, NULL if an error occurred.
213 */
214
215 ASC_DLLSPEC void *pool_get_element(pool_store_t ps);
216 /**<
217 * Get a usable element from the pool.
218 * Returns a void pointer to a blob of memory of the eltsize
219 * set when ps was created. You must cast it appropriately.
220 * The blob data is not initialized in any particular way.
221 *
222 * @param ps The pool store from which to retrieve an element.
223 * If ps is NULL, then an error message is printed
224 * and NULL is returned.
225 * @return A pointer to the usable element, or NULL iff ps is NULL or
226 * store growth is required and the operating system is unable
227 * to allocate the required memory.
228 */
229
230 extern void pool_get_element_list(pool_store_t ps,
231 int len,
232 void **ellist);
233 /**<
234 * NOT IMPLEMENTED.
235 *
236 * Takes the pointer array, ellist, of length len provided by the user
237 * and fills it with pointers to elements from the store.
238 * There is not necessarily any relation (memory map wise) between the
239 * locations pointed to by successive entries in the ellist returned.
240 * Ellist should point to an array with enough space for len pointers.
241 * Returns NULL in ellist[0] iff store growth is required and the operating
242 * system is unable to allocate the required memory.<br><br>
243 *
244 * The user is reminded that if he knows how many elements he needs
245 * ahead of time, he is probably better off mallocing the array himself.
246 *
247 * @todo Implement general/pool.c:pool_get_element_list() of remove
248 * it from pool.h.
249 */
250
251 #define pool_DEBUG FALSE
252 /**<
253 * Flag controlling extra checking of the pool management routines.
254 * Setting pool_DEBUG to TRUE causes the pool_store routines to do
255 * some RATHER expensive checking. It should be set to FALSE.
256 */
257 #define pool_LIGHTENING FALSE
258 /**<
259 * Flag controlling extent of internal sanity checking.
260 * Setting pool_LIGHTENING to TRUE causes pool_store routines to assume
261 * the user is perfect: i.e. no sanity checks are at all necessary and most
262 * internal accounting can be disabled. No one with an ounce of sanity
263 * would ever set this flag to TRUE unless the code using the
264 * pool module was proven bug free. It makes the allocator smaller
265 * and faster, though, by ~15%. <br><br>
266 *
267 * This flag exists to make it easy to test the theory that the
268 * accounting overhead in this code is not of significant cost.
269 * Below 1e5 elements it really isn't bad enough to justify the
270 * assumption that the user is perfect.
271 */
272
273 #if pool_DEBUG
274 #define pool_free_element(ps,eltpointer) pool_free_elementF((ps),(eltpointer),__FILE__)
275 #else
276 #define pool_free_element(ps,eltpointer) pool_free_elementF((ps),(eltpointer))
277 #endif
278 /**<
279 * Releases an element back to the store.
280 * If you return the same pointer twice, we will have
281 * no qualms about returning it to you twice. We won't necessarily
282 * return it to you twice, though.<br><br>
283 *
284 * If pool_DEBUG is TRUE, eltpointer will be checked for belonging
285 * to ps. If you call pool_free_element() with a pointer the ps does
286 * not recognize, it will not be freed and a message will be
287 * sent to ASCERR.<br><br>
288 *
289 * If pool_DEBUG is FALSE, eltpointer will be assumed to belong
290 * with the ps in question. The implications of handing
291 * pool_free_element() an element of the wrong size or from the
292 * wrong ps (bearing in mind the LIFO reuse of elements) should be
293 * obvious. If they are not, stop using these routines.<br><br>
294 *
295 * If at any time the number of elements freed exceeds the number
296 * handed out, we will whine (unless pool_LIGHTENING). If ps is
297 * NULL, and error message is printed and the function returns.
298 * If eltpointer is NULL, we will ignore it completely.
299 *
300 * @param ps pool_store_t, the pool store to modify.
301 * @param eltpointer void*, the element to return to the pool.
302 * @return No return value.
303 * @see pool_free_elementF()
304 */
305
306 ASC_DLLSPEC void pool_free_elementF(pool_store_t ps, void * eltpointer
307 #if pool_DEBUG
308 ,CONST char *file
309 #endif
310 );
311 /**<
312 * Implementation function for pool_free_element().
313 * Do not call this function directly - use pool_free_element() instead.
314 */
315
316 #if pool_DEBUG
317 #define pool_clear_store(ps) pool_clear_storeF((ps),__FILE__)
318 #else
319 #define pool_clear_store(ps) pool_clear_storeF(ps)
320 #endif
321 /**<
322 * Clears the books in ps. That is, we reset the ps to think
323 * that __all__ elements are freshly available and have never
324 * been handed out. If ps is NULL, an error message is printed
325 * and the function returns.<br><br>
326 *
327 * If pool_DEBUG is TRUE, it first verifies that all elements have
328 * been pool_freed first and whines if not.
329 * Get and free calls will be balanced to see if spurious elements
330 * have been handed in. (This is a heuristic check).
331 * The clear process will cause any spurious pointers that were
332 * turned in via pool_free_element() to be forgotten about.<br><br>
333 *
334 * Clearing a store is not necessary for pool_destroy_store().
335 * Recycling is faster from the recycle list than from a cleared store, ~2%.
336 * Clear is provided for users who want to obtain elements with a higher
337 * probability of successive elements being near each other.
338 *
339 * @param ps pool_store_t, the pool store to clear.
340 * @return No return value.
341 * @see pool_clear_storeF()
342 */
343
344 ASC_DLLSPEC void pool_clear_storeF(pool_store_t ps
345 #if pool_DEBUG
346 , CONST char *file
347 #endif
348 );
349 /**<
350 * Implementation function for pool_clear_store().
351 * Do not call this function directly - use pool_clear_store() instead.
352 */
353
354 ASC_DLLSPEC void pool_destroy_store(pool_store_t ps);
355 /**<
356 * Deallocates everything associated with the ps.
357 * If pool_DEBUG is TRUE, it first verifies that all elements
358 * have been pool_freed first and whines if not.
359 * If pool_DEBUG is FALSE, just nukes everything unconditionally.
360 * If ps is NULL, an error message is printed and the function
361 * returns.
362 *
363 * @param ps The pool store to destroy.
364 */
365
366 extern void pool_print_store(FILE *fp, pool_store_t ps, unsigned detail);
367 /**<
368 * Prints statistics about a pool_store_t to the file stream given.
369 * Which stats get printed depends on detail.
370 * - If detail 0, displays just summary statistics.
371 * - If detail 1, just internal statistics.
372 * - If detail >1, displays both.
373 *
374 * @param fp The open file stream on which to print the report.
375 * @param ps The pool store on which to report.
376 * @param detail The level of detail to print:
377 * 0 = summary, 1 = internal stats, >1 = both.
378 */
379
380 extern size_t pool_sizeof_store(pool_store_t ps);
381 /**<
382 * Retrieves the current total byte usage of the store.
383 * Returns 0 if an invalid pool store is specified.
384 *
385 * @param ps pool_store_t, the pool store to query.
386 * @return The total bytes currently used by the pool store.
387 */
388
389 #endif /* ASC_POOL_H */
390

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22