|
|
1.1 root 1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: #include <kernel/st_alloc.h>
5:
6:
7: /*
8: * Work around some deficiencies in the UNIX library w.r.t. Borland.
9: */
10:
11: #if __BORLANDC__
12:
13: #define RANDOM(n) random (n)
14: #define RANDOMIZE() randomize ()
15:
16: #else
17:
18: /*
19: * While this function is not part of POSIX, many implementations provide
20: * it; random (n) returns a random integer in the range of 0 to (n - 1).
21: *
22: * Note that (rand () % n) is not a sufficient implementation, as the
23: * distribution of (rand () % n) will not be uniform for n not a power of 2.
24: * For instance, with n = 2*RAND_MAX/3, using the modulus will cause the
25: * numbers from 0 to RAND_MAX/2 - 1 to occur twice as often as the second
26: * half of the range.
27: *
28: * The expression "(int) ((long) rand () * range / (RAND_MAX + 1))" as used
29: * by Borland works to distribute the error uniformly across the range 0 to
30: * n-1, but still can cause certain numbers to have a higher probability
31: * than their neighbours.
32: *
33: * The following system minimizes the error at the expense of execution
34: * time by simply throwing away those numbers that cause the error, ie those
35: * numbers from RAND_MAX down to RAND_MAX - ((RAND_MAX + 1) % n). A more
36: * efficient system might use more bits from the LCG, but this works fine.
37: */
38:
39: static int RANDOM (int range) {
40: int error, num;
41:
42: if (range <= 0)
43: return 0;
44:
45: error = ((unsigned) RAND_MAX + 1) % range;
46:
47: while ((num = rand ()) > RAND_MAX - error)
48: ;
49:
50: return num % range;
51: }
52:
53: #include <time.h>
54:
55: /*
56: * And similarly for the randomize () function, which kicks off random number
57: * generation.
58: */
59:
60: static void RANDOMIZE (void) {
61: srand ((int) time (NULL));
62: }
63:
64: #endif /* ! __BORLANDC__ */
65:
66:
67: /*
68: * Dump some arena internals out...
69: */
70:
71: void st_dump (_ST_HEAP_CONTROL_P q) {
72: _ST_ADDR_T scan = _ST_HEAP_FIRST (q, 0);
73: int count, size, cntl;
74:
75: do {
76: size = count = 0;
77: while (! _ST_BLOCK_FREE (cntl = _ST_BLOCK_CONTROL (q, scan))) {
78: size += _ST_BLOCK_SIZE (cntl);
79: count ++;
80: if (_ST_HEAP_NEXT (scan, cntl) >= q->_arena_end)
81: break;
82: scan = _ST_HEAP_NEXT (scan, cntl);
83: }
84: printf ("%d allocated blocks of total size %d\n", count, size);
85:
86: if (! _ST_BLOCK_FREE (cntl))
87: break;
88:
89: size = count = 0;
90: while (_ST_BLOCK_FREE (cntl = _ST_BLOCK_CONTROL (q, scan))) {
91: size += _ST_BLOCK_SIZE (cntl);
92: count ++;
93: if (_ST_HEAP_NEXT (scan, cntl) >= q->_arena_end)
94: break;
95: scan = _ST_HEAP_NEXT (scan, cntl);
96: }
97: printf ("%d free blocks of size %d\n", count, size);
98: } while (_ST_HEAP_NEXT (scan, cntl) < q->_arena_end);
99: }
100:
101: /*
102: * Dump a small selection of buckets in great detail.
103: */
104:
105: void st_detail (_ST_HEAP_CONTROL_P q, int frombkt, int tobkt) {
106: _ST_ADDR_T scan = _ST_HEAP_FIRST (q, frombkt);
107: int i;
108:
109: while (scan < _ST_HEAP_FIRST (q, tobkt + 1)) {
110: if ((i = _ST_HEAP_BUCKET (q, scan)) >= frombkt)
111: while (frombkt <= i)
112: printf ("\nBucket %d, %d biggest free, entry @ %04x : ",
113: frombkt ++,
114: _ST_HEAP_BIGGEST (q, frombkt + q->_buckets_inuse),
115: scan);
116: i = _ST_BLOCK_CONTROL (q, scan);
117: printf (_ST_BLOCK_FREE (i) ? "Free %04x (%d) : " :
118: "Used %04x (%d) : ",
119: scan, _ST_BLOCK_SIZE (i));
120: scan = _ST_HEAP_NEXT (scan, i);
121: }
122: }
123:
124:
125: /*
126: * An assertion mechanism for testing the allocator.
127: */
128:
129: #define ASSERT(q,x,i) (! (x) ? st_fatal (q,i, __LINE__) : (void) 0)
130:
131: static void st_fatal (_ST_HEAP_CONTROL_P q, int i, int line) {
132:
133: printf ("Assertion failure at line %d of file " __FILE__ "\n", line);
134: printf ("Iteration number #%d\n", i);
135:
136: st_dump (q);
137:
138: abort ();
139: }
140:
141:
142: /*
143: * Exercise the heap allocator. We exercise the allocator down to the last
144: * byte, and define the following relationships so we can assume that by the
145: * time we have done TEST_ALLOCS allocations of TEST_ALLOC_SIZE, then we have
146: * consumed all free memory.
147: *
148: * The _ST_WORD_T factor in the TOTALWORDS calculation is for the block
149: * headers used internally by the allocator. The _ST_ADDR_T factor is for the
150: * addr [] array, which is also taken from the managed area. The "+ 2" factor
151: * is for the block headers for (i) the dummy block at the start of the arena
152: * and (ii) the block header for the addr [] block.
153: */
154:
155: #define TEST_ALLOCS 2000 /* number of allocations */
156: #define TEST_ALLOC_SIZE 16 /* in bytes */
157: #define SEGMENTS 256 /* how many partitions in the space */
158:
159: #define TOTALWORDS (TEST_ALLOCS * (TEST_ALLOC_SIZE + sizeof (_ST_WORD_T)\
160: + sizeof (_ST_ADDR_T)) / sizeof (_ST_WORD_T)\
161: + 2)
162:
163: void main (int argc, char ** argv) {
164: _ST_HEAP_CONTROL_P q;
165: void * mem;
166: _ST_ADDR_T * addr;
167: int i, base, leave;
168: int forward = 0, back = 0, shuffle = 1;
169: int growup = 1, growdown = 1, growboth = 1, growmove = 1, shrink = 1;
170:
171: RANDOMIZE ();
172:
173: printf ("TOTALWORDS = %d\n", TOTALWORDS);
174:
175: for (i = 1 ; i < argc ; i ++)
176: if (argv [i][0] == '-')
177: switch (argv [i][1]) {
178:
179: case 'f':
180: forward = argv [i][2] == 0 ? 1 : atoi (argv [i] + 2);
181: break;
182:
183: case 'b':
184: back = argv [i][2] == 0 ? 1 : atoi (argv [i] + 2);
185: break;
186:
187: case 'r':
188: shuffle = argv [i][2] == 0 ? 1 : atoi (argv [i] + 2);
189: break;
190:
191: case 'l':
192: leave = argv [i][2] == 0 ? 1 : atoi (argv [i] + 2);
193: break;
194: }
195:
196: q = (_ST_HEAP_CONTROL_P) malloc (_ST_HEAP_CONTROL_SIZE (SEGMENTS));
197: mem = malloc (TOTALWORDS * sizeof (_ST_WORD_T));
198:
199: st_ctor (q, SEGMENTS, TOTALWORDS, (_ST_ADDR_T) mem);
200:
201: st_assert (q);
202:
203: printf ("Using qheap : ");
204:
205: /*
206: * Initially, why not get this space from the test arena ?
207: */
208:
209: addr = (_ST_ADDR_T *) st_new (q, TEST_ALLOCS * sizeof (* addr));
210:
211:
212: /*
213: * Exercises for realloc (), growing blocks up.
214: */
215:
216: while (growup -- > 0) {
217: for (i = 0 ; i < TEST_ALLOCS ; i ++) {
218: addr [i] = st_new (q, TEST_ALLOC_SIZE);
219: ASSERT (q, addr [i] != NULL, i);
220: }
221:
222: for (i = 0 ; i < TEST_ALLOCS ; i += 2) {
223: ASSERT (q, st_disp (q, addr [i + 1]
224: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
225:
226: addr [i + 1] = st_realloc (q, addr [i], 2 * TEST_ALLOC_SIZE
227: ST_FREE_SIZE (TEST_ALLOC_SIZE));
228: ASSERT (q, addr [i + 1] == addr [i], i);
229:
230: ASSERT (q, st_disp (q, addr [i]
231: ST_FREE_SIZE (2 * TEST_ALLOC_SIZE)) == 0, i);
232: }
233: }
234:
235: st_dump (q);
236:
237:
238: /*
239: * Exercises for realloc (), growing blocks down.
240: */
241:
242: while (growdown -- > 0) {
243: _ST_ADDR_T temp;
244:
245: for (i = 0 ; i < TEST_ALLOCS ; i ++) {
246: addr [i] = st_new (q, TEST_ALLOC_SIZE);
247: ASSERT (q, addr [i] != NULL, i);
248: }
249:
250: temp = addr [0];
251:
252: for (i = 0 ; i < TEST_ALLOCS - 1 ; i += 2) {
253: ASSERT (q, st_disp (q, addr [i]
254: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
255:
256: /* put a pattern in the block to be moved */
257:
258: * addr [i + 1] = (_ST_WORD_T) addr [i + 1];
259:
260: ASSERT (q,
261: st_realloc (q, addr [i + 1], 2 * TEST_ALLOC_SIZE
262: ST_FREE_SIZE (TEST_ALLOC_SIZE))
263: == temp, i);
264:
265: /* check that the data was moved correctly */
266:
267: ASSERT (q, * temp == (_ST_WORD_T) addr [i + 1], i);
268:
269: ASSERT (q, st_disp (q, temp
270: ST_FREE_SIZE (2 * TEST_ALLOC_SIZE)) == 0, i);
271:
272: if (st_assert (q) != 0) {
273: printf ("error %s, i = %d\n",
274: _ST_HEAP_ERROR (q), i);
275: st_dump (q);
276: return;
277: }
278:
279: }
280: }
281:
282: st_dump (q);
283:
284:
285: /*
286: * Exercises for realloc (), growing blocks both up and down.
287: */
288:
289: while (growboth -- > 0) {
290:
291: for (i = 0 ; i < TEST_ALLOCS ; i ++) {
292: addr [i] = st_new (q, TEST_ALLOC_SIZE);
293: ASSERT (q, addr [i] != NULL, i);
294: }
295:
296: for (i = 0 ; i < TEST_ALLOCS - 3 ; i += 4) {
297: ASSERT (q, st_disp (q, addr [i]
298: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
299:
300: if (st_assert (q) != 0) {
301: printf ("st_disp () #1 error %s, i = %d\n",
302: _ST_HEAP_ERROR (q), i);
303: st_dump (q);
304: return;
305: }
306:
307: ASSERT (q, st_disp (q, addr [i + 2]
308: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
309:
310: if (st_assert (q) != 0) {
311: printf ("st_disp () #2 error %s, i = %d\n",
312: _ST_HEAP_ERROR (q), i);
313: st_dump (q);
314: return;
315: }
316:
317: /* put a pattern in the block to be moved */
318:
319: * addr [i + 1] = (_ST_WORD_T) addr [i + 1];
320:
321: ASSERT (q, st_realloc (q, addr [i + 1], 3 * TEST_ALLOC_SIZE
322: ST_FREE_SIZE (TEST_ALLOC_SIZE))
323: == addr [i], i);
324:
325: /* check that the data was moved correctly */
326:
327: ASSERT (q, * addr [i] == (_ST_WORD_T) addr [i + 1], i);
328:
329: if (st_assert (q) != 0) {
330: printf ("error %s, i = %d\n",
331: _ST_HEAP_ERROR (q), i);
332: st_dump (q);
333: return;
334: }
335: }
336:
337: for (i = 0 ; i < TEST_ALLOCS - 3 ; i += 4) {
338: ASSERT (q, st_disp (q, addr [i]
339: ST_FREE_SIZE (3 * TEST_ALLOC_SIZE)) == 0, i);
340: ASSERT (q, st_disp (q, addr [i + 3]
341: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
342: }
343: }
344:
345: st_dump (q);
346:
347:
348: /*
349: * Perform a given number of allocations and shuffled decallocations,
350: * leaving behind a certain number of allocated blocks to clutter the
351: * arena for the next set.
352: */
353:
354: leave = base = 0;
355: while (shuffle -- > 0) {
356: for (i = base ; i < TEST_ALLOCS ; i ++) {
357: addr [i] = st_new (q, TEST_ALLOC_SIZE);
358: if (st_assert (q) != 0) {
359: printf ("Alloc error %s, %d blocks remaining",
360: _ST_HEAP_ERROR (q), i);
361: return;
362: }
363: ASSERT (q, addr [i] != NULL, i);
364: }
365:
366: base = shuffle > 0 ? leave : 0;
367:
368: for (i = TEST_ALLOCS ; i -- > base ;) {
369:
370: /*
371: * Pick an element to free, then exchange that for
372: * the last element, thereby shortening the list.
373: */
374:
375: int elem = RANDOM (i + 1);
376: ASSERT (q, st_disp (q, addr [elem]
377: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
378: if (st_assert (q) != 0) {
379: printf ("Free error %s, %d blocks remaining",
380: _ST_HEAP_ERROR (q), i);
381: return;
382: }
383: addr [elem] = addr [i];
384: }
385: }
386:
387: st_dump (q);
388:
389:
390: /*
391: * Deallocate from the bottom to the top.
392: */
393:
394: while (forward -- > 0) {
395: for (i = 0 ; i < TEST_ALLOCS ; i ++) {
396: addr [i] = st_new (q, TEST_ALLOC_SIZE);
397: ASSERT (q, addr [i] != NULL, i);
398: }
399:
400: for (i = 0 ; i < TEST_ALLOCS ; i ++)
401: ASSERT (q, st_disp (q, addr [i]
402: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
403: }
404:
405:
406: /*
407: * Deallocate from the top to the bottom.
408: */
409:
410: while (back -- > 0) {
411: for (i = 0 ; i < TEST_ALLOCS ; i ++) {
412: addr [i] = st_new (q, TEST_ALLOC_SIZE);
413: ASSERT (q, addr [i] != NULL, i);
414: }
415:
416: for (i = TEST_ALLOCS ; i -- > 0 ;)
417: ASSERT (q, st_disp (q, addr [i]
418: ST_FREE_SIZE (TEST_ALLOC_SIZE)) == 0, i);
419: }
420: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.