|
|
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.