os161-1.99
 All Data Structures
malloctest.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /* 
00031  * malloctest.c
00032  *
00033  * This program contains a variety of tests for malloc and free.
00034  * XXX most tests leak on error.
00035  *
00036  * These tests (subject to restrictions and limitations noted below) should
00037  * work once user-level malloc is implemented.
00038  */
00039 
00040 #include <stdint.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <unistd.h>
00044 #include <fcntl.h>
00045 #include <err.h>
00046 
00047 
00048 #define _PATH_RANDOM   "random:"
00049 
00050 #define SMALLSIZE   72
00051 #define MEDIUMSIZE  896
00052 #define BIGSIZE     16384
00053 #define HUGESIZE    (1024 * 1024 * 1024)
00054 
00055 /* Maximum amount of space per block we allow for indexing structures */
00056 #define OVERHEAD         32
00057 
00058 /* Point past which we assume something else is going on */
00059 #define ABSURD_OVERHEAD  256
00060 
00061 static
00062 int
00063 geti(void)
00064 {
00065         int val=0;
00066         int ch, digits=0;
00067 
00068         while (1) {
00069                 ch = getchar();
00070                 if (ch=='\n' || ch=='\r') {
00071                         putchar('\n');
00072                         break;
00073                 }
00074                 else if ((ch=='\b' || ch==127) && digits>0) {
00075                         printf("\b \b");
00076                         val = val/10;
00077                         digits--;
00078                 }
00079                 else if (ch>='0' && ch<='9') {
00080                         putchar(ch);
00081                         val = val*10 + (ch-'0');
00082                         digits++;
00083                 }
00084                 else {
00085                         putchar('\a');
00086                 }
00087         }
00088 
00089         if (digits==0) {
00090                 return -1;
00091         }
00092         return val;
00093 }
00094 
00095 ////////////////////////////////////////////////////////////
00096 
00097 /*
00098  * Fill a block of memory with a test pattern.
00099  */
00100 static
00101 void
00102 markblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
00103 {
00104         size_t n, i;
00105         unsigned long *pl;
00106         unsigned long val;
00107 
00108         pl = (unsigned long *)ptr;
00109         n = size / sizeof(unsigned long);
00110 
00111         for (i=0; i<n; i++) {
00112                 val = ((unsigned long)i ^ (unsigned long)bias);
00113                 pl[i] = val;
00114                 if (doprint && (i%64==63)) {
00115                         printf(".");
00116                 }
00117         }
00118         if (doprint) {
00119                 printf("\n");
00120         }
00121 }
00122 
00123 /*
00124  * Check a block marked with markblock()
00125  */
00126 static
00127 int
00128 checkblock(volatile void *ptr, size_t size, unsigned bias, int doprint)
00129 {
00130         size_t n, i;
00131         unsigned long *pl;
00132         unsigned long val;
00133 
00134         pl = (unsigned long *)ptr;
00135         n = size / sizeof(unsigned long);
00136 
00137         for (i=0; i<n; i++) {
00138                 val = ((unsigned long)i ^ (unsigned long)bias);
00139                 if (pl[i] != val) {
00140                         if (doprint) {
00141                                 printf("\n");
00142                         }
00143                         printf("FAILED: data mismatch at offset %lu of block "
00144                                "at 0x%lx: %lu vs. %lu\n",
00145                                (unsigned long) (i*sizeof(unsigned long)),
00146                                (unsigned long)(uintptr_t)pl,
00147                                pl[i], val);
00148                         return -1;
00149                 }
00150                 if (doprint && (i%64==63)) {
00151                         printf(".");
00152                 }
00153         }
00154         if (doprint) {
00155                 printf("\n");
00156         }
00157 
00158         return 0;
00159 }
00160 
00161 ////////////////////////////////////////////////////////////
00162 
00163 /*
00164  * Test 1
00165  *
00166  * This test checks if all the bytes we asked for are getting
00167  * allocated.
00168  */
00169 
00170 static
00171 void
00172 test1(void)
00173 {
00174         volatile unsigned *x;
00175 
00176         printf("*** Malloc test 1 ***\n");
00177         printf("Allocating %u bytes\n", BIGSIZE);
00178         x = malloc(BIGSIZE);
00179         if (x==NULL) {
00180                 printf("FAILED: malloc failed\n");
00181                 return;
00182         }
00183 
00184         markblock(x, BIGSIZE, 0, 0);
00185         if (checkblock(x, BIGSIZE, 0, 0)) {
00186                 printf("FAILED: data corrupt\n");
00187                 return;
00188         }
00189 
00190         free((void *)x);
00191 
00192         printf("Passed malloc test 1.\n");
00193 }
00194 
00195 
00196 ////////////////////////////////////////////////////////////
00197 
00198 /* 
00199  * Test 2
00200  *
00201  * Tests if malloc gracefully handles failing requests.
00202  *
00203  * This test assumes that one of the following conditions holds:
00204  *    1. swap is not overcommitted; or
00205  *    2. user processes are limited to some maximum size, and enough
00206  *       swap exists to hold a maximal user process.
00207  *
00208  * That is, it assumes that malloc returns NULL when out of memory,
00209  * and that the process will not be killed for running out of
00210  * memory/swap at other times.
00211  *
00212  * If mallocing more memory than the system can actually provide
00213  * backing for succeeds, this test will blow up. That's ok, but please
00214  * provide a way to switch on one of the above conditions so this test
00215  * can be run.
00216  *
00217  * This test works by trying a huge malloc, and then trying
00218  * successively smaller mallocs until one works. Then it touches the
00219  * whole block to make sure the memory is actually successfully
00220  * allocated. Then it frees the block and allocates it again, which
00221  * should succeed.
00222  *
00223  * Note that this test may give spurious failures if anything else is
00224  * running at the same time and changing the amount of memory
00225  * available.
00226  */
00227 
00228 static
00229 void
00230 test2(void)
00231 {
00232         volatile unsigned *x;
00233         size_t size;
00234         
00235         printf("Entering malloc test 2.\n");
00236         printf("Make sure you read and understand the comment in malloctest.c "
00237                "that\nexplains the conditions this test assumes.\n\n");
00238 
00239         printf("Testing how much memory we can allocate:\n");
00240         
00241         for (size = HUGESIZE; (x = malloc(size))==NULL; size = size/2) {
00242                 printf("  %9lu bytes: failed\n", (unsigned long) size);
00243         }
00244         printf("  %9lu bytes: succeeded\n", (unsigned long) size);
00245 
00246         printf("Passed part 1\n");
00247 
00248         printf("Touching all the words in the block.\n");
00249         markblock(x, size, 0, 1);
00250 
00251         printf("Validating the words in the block.\n");
00252         if (checkblock(x, size, 0, 1)) {
00253                 printf("FAILED: data corrupt\n");
00254                 return;
00255         }
00256         printf("Passed part 2\n");
00257 
00258 
00259         printf("Freeing the block\n");
00260         free((void *)x);
00261         printf("Passed part 3\n");
00262         printf("Allocating another block\n");
00263         
00264         x = malloc(size);
00265         if (x==NULL) {
00266                 printf("FAILED: free didn't return the memory?\n");
00267                 return;
00268         }
00269         free((void *)x);
00270 
00271         printf("Passed malloc test 2.\n");
00272 }
00273 
00274 
00275 ////////////////////////////////////////////////////////////
00276 
00277 /* 
00278  * Test 3
00279  *
00280  * Tests if malloc gracefully handles failing requests.
00281  *
00282  * This test assumes the same conditions as test 2.
00283  *
00284  * This test works by mallocing a lot of small blocks in a row until
00285  * malloc starts failing.
00286  */
00287 
00288 struct test3 {
00289         struct test3 *next;
00290         char junk[(SMALLSIZE - sizeof(struct test3 *))];
00291 };
00292 
00293 static
00294 void
00295 test3(void)
00296 {
00297         struct test3 *list = NULL, *tmp;
00298         size_t tot=0;
00299         int ct=0, failed=0;
00300         void *x;
00301 
00302         printf("Entering malloc test 3.\n");
00303         printf("Make sure you read and understand the comment in malloctest.c "
00304                "that\nexplains the conditions this test assumes.\n\n");
00305 
00306         printf("Testing how much memory we can allocate:\n");
00307 
00308         while ((tmp = malloc(sizeof(struct test3))) != NULL) {
00309 
00310                 tmp->next = list;
00311                 list = tmp;
00312 
00313                 tot += sizeof(struct test3);
00314 
00315                 markblock(list->junk, sizeof(list->junk), (uintptr_t)list, 0);
00316 
00317                 ct++;
00318                 if (ct%128==0) {
00319                         printf(".");
00320                 }
00321         }
00322 
00323         printf("Allocated %lu bytes\n", (unsigned long) tot);
00324 
00325         printf("Trying some more allocations which I expect to fail...\n");
00326 
00327         x = malloc(SMALLSIZE);
00328         if (x != NULL) {
00329                 printf("FAILED: malloc(%u) succeeded\n", SMALLSIZE);
00330                 return;
00331         }
00332 
00333         x = malloc(MEDIUMSIZE);
00334         if (x != NULL) {
00335                 printf("FAILED: malloc(%u) succeeded\n", MEDIUMSIZE);
00336                 return;
00337         }
00338 
00339         x = malloc(BIGSIZE);
00340         if (x != NULL) {
00341                 printf("FAILED: malloc(%u) succeeded\n", BIGSIZE);
00342                 return;
00343         }
00344 
00345         printf("Ok, now I'm going to free everything...\n");
00346 
00347         while (list != NULL) {
00348                 tmp = list->next;
00349 
00350                 if (checkblock(list->junk, sizeof(list->junk), 
00351                                (uintptr_t)list, 0)) {
00352                         failed = 1;
00353                 }
00354 
00355                 free(list);
00356                 list = tmp;
00357         }
00358 
00359         if (failed) {
00360                 printf("FAILED: data corruption\n");
00361                 return;
00362         }
00363 
00364         printf("Let me see if I can allocate some more now...\n");
00365 
00366         x = malloc(MEDIUMSIZE);
00367         if (x == NULL) {
00368                 printf("FAIL: Nope, I couldn't.\n");
00369                 return;
00370         }
00371         free(x);
00372         
00373         printf("Passed malloc test 3\n");
00374 }
00375 
00376 ////////////////////////////////////////////////////////////
00377 
00378 /*
00379  * Test 4
00380  *
00381  * Tries to test in detail if malloc coalesces the free list properly.
00382  *
00383  * This test will likely fail if something other than a basic first-fit/
00384  * next-fit/best-fit algorithm is used.
00385  */
00386 
00387 static
00388 void
00389 test4(void)
00390 {
00391         void *x, *y, *z;
00392         unsigned long lx, ly, lz, overhead, zsize;
00393 
00394         printf("Entering malloc test 4.\n");
00395         printf("This test is intended for first/best-fit based mallocs.\n");
00396         printf("This test may not work correctly if run after other tests.\n");
00397 
00398         printf("Testing free list coalescing:\n");
00399 
00400         x = malloc(SMALLSIZE);
00401         if (x==NULL) {
00402                 printf("FAILED: malloc(%u) failed\n", SMALLSIZE);
00403                 return;
00404         }
00405 
00406         y = malloc(MEDIUMSIZE);
00407         if (y==NULL) {
00408                 printf("FAILED: malloc(%u) failed\n", MEDIUMSIZE);
00409                 return;
00410         }
00411 
00412         if (sizeof(unsigned long) < sizeof(void *)) {
00413                 printf("Buh? I can't fit a void * in an unsigned long\n");
00414                 printf("ENVIRONMENT FAILED...\n");
00415                 return;
00416         }
00417 
00418         lx = (unsigned long)x;
00419         ly = (unsigned long)y;
00420 
00421         printf("x is 0x%lx; y is 0x%lx\n", lx, ly);
00422 
00423         /*
00424          * The memory should look something like this:
00425          *
00426          *     OXXXOYYYYYYYYYYY
00427          *
00428          * where O are optional overhead (indexing) blocks.
00429          */
00430 
00431         /* This is obviously wrong. */
00432         if (lx == ly) {
00433                 printf("FAIL: x == y\n");
00434                 return;
00435         }
00436 
00437         /*
00438          * Check for overlap. It is sufficient to check if the start
00439          * of each block is within the other block. (If the end of a
00440          * block is within the other block, either the start is too,
00441          * or the other block's start is within the first block.)
00442          */
00443         if (lx < ly && lx + SMALLSIZE > ly) {
00444                 printf("FAIL: y starts within x\n");
00445                 return;
00446         }
00447         if (ly < lx && ly + MEDIUMSIZE > lx) {
00448                 printf("FAIL: x starts within y\n");
00449                 return;
00450         }
00451 
00452         /*
00453          * If y is lower than x, some memory scheme we don't
00454          * understand is in use, or else there's already stuff on the
00455          * free list.
00456          */
00457         if (ly < lx) {
00458                 printf("TEST UNSUITABLE: y is below x\n");
00459                 return;
00460         }
00461 
00462         /*
00463          * Compute the space used by index structures.
00464          */
00465         overhead = ly - (lx + SMALLSIZE);
00466         printf("Apparent block overhead: %lu\n", overhead);
00467 
00468         if (overhead > ABSURD_OVERHEAD) {
00469                 printf("TEST UNSUITABLE: block overhead absurdly large.\n");
00470                 return;
00471         }
00472         if (overhead > OVERHEAD) {
00473                 printf("FAIL: block overhead is too large.\n");
00474                 return;
00475         }
00476 
00477         printf("Freeing blocks...\n");
00478         free(x);
00479         free(y);
00480 
00481         zsize = SMALLSIZE + MEDIUMSIZE + overhead;
00482 
00483         printf("Now allocating %lu bytes... should reuse the space.\n", zsize);
00484         z = malloc(zsize);
00485         if (z == NULL) {
00486                 printf("FAIL: Allocation failed...\n");
00487                 return;
00488         }
00489 
00490         lz = (unsigned long) z;
00491 
00492         printf("z is 0x%lx (x was 0x%lx, y 0x%lx)\n", lz, lx, ly);
00493 
00494         if (lz==lx) {
00495                 printf("Passed.\n");
00496         }
00497         else {
00498                 printf("Failed.\n");
00499         }
00500 
00501         free(z);
00502 }
00503 
00504 ////////////////////////////////////////////////////////////
00505 
00506 /*
00507  * Test 5/6/7
00508  *
00509  * Generally beats on malloc/free.
00510  *
00511  * Test 5 uses random seed 0.
00512  * Test 6 seeds the random number generator from random:.
00513  * Test 7 asks for a seed.
00514  */
00515 
00516 static
00517 void
00518 test567(int testno, unsigned long seed)
00519 {
00520         static const int sizes[8] = { 13, 17, 69, 176, 433, 871, 1150, 6060 };
00521         
00522         void *ptrs[32];
00523         int psizes[32];
00524         int i, n, size, failed=0;
00525 
00526         srandom(seed);
00527         printf("Seeded random number generator with %lu.\n", seed);
00528 
00529         for (i=0; i<32; i++) {
00530                 ptrs[i] = NULL;
00531                 psizes[i] = 0;
00532         }
00533 
00534         for (i=0; i<100000; i++) {
00535                 n = random()%32;
00536                 if (ptrs[n] == NULL) {
00537                         size = sizes[random()%8];
00538                         ptrs[n] = malloc(size);
00539                         psizes[n] = size;
00540                         if (ptrs[n] == NULL) {
00541                                 printf("\nmalloc %u failed\n", size);
00542                                 failed = 1;
00543                                 break;
00544                         }
00545                         markblock(ptrs[n], size, n, 0);
00546                 }
00547                 else {
00548                         size = psizes[n];
00549                         if (checkblock(ptrs[n], size, n, 0)) {
00550                                 failed = 1;
00551                                 break;
00552                         }
00553                         free(ptrs[n]);
00554                         ptrs[n] = NULL;
00555                         psizes[n] = 0;
00556                 }
00557                 if (i%256==0) {
00558                         printf(".");
00559                 }
00560         }
00561         printf("\n");
00562 
00563         for (i=0; i<32; i++) {
00564                 if (ptrs[i] != NULL) {
00565                         free(ptrs[i]);
00566                 }
00567         }
00568 
00569         if (failed) {
00570                 printf("FAILED malloc test %d\n", testno);
00571         }
00572         else {
00573                 printf("Passed malloc test %d\n", testno);
00574         }
00575 }
00576 
00577 static
00578 void
00579 test5(void)
00580 {
00581         printf("Beginning malloc test 5\n");
00582         test567(5, 0);
00583 }
00584 
00585 static
00586 void
00587 test6(void)
00588 {
00589         int fd, len;
00590         unsigned long seed;
00591 
00592         printf("Beginning malloc test 6\n");
00593 
00594         fd = open(_PATH_RANDOM, O_RDONLY);
00595         if (fd < 0) {
00596                 err(1, "%s", _PATH_RANDOM);
00597         }
00598         len = read(fd, &seed, sizeof(seed));
00599         if (len < 0) {
00600                 err(1, "%s", _PATH_RANDOM);
00601         }
00602         else if (len < (int)sizeof(seed)) {
00603                 errx(1, "%s: Short read", _PATH_RANDOM);
00604         }
00605         close(fd);
00606 
00607         test567(6, seed);
00608 }
00609 
00610 static
00611 void
00612 test7(void)
00613 {
00614         unsigned long seed;
00615 
00616         printf("Beginning malloc test 7\n");
00617 
00618         printf("Enter random seed: ");
00619         seed = geti();
00620 
00621         test567(7, seed);
00622 }
00623 
00624 ////////////////////////////////////////////////////////////
00625 
00626 static struct {
00627         int num;
00628         const char *desc;
00629         void (*func)(void);
00630 } tests[] = {
00631         { 1, "Simple allocation test", test1 },
00632         { 2, "Allocate all memory in a big chunk", test2 },
00633         { 3, "Allocate all memory in small chunks", test3 },
00634         { 4, "Free list coalescing test (first/next/best-fit only)", test4 },
00635         { 5, "Stress test", test5 },
00636         { 6, "Randomized stress test", test6 },
00637         { 7, "Stress test with particular seed", test7 },
00638         { -1, NULL, NULL }
00639 };
00640 
00641 static
00642 int
00643 dotest(int tn)
00644 {
00645         int i;
00646         for (i=0; tests[i].num>=0; i++) {
00647                 if (tests[i].num == tn) {
00648                         tests[i].func();
00649                         return 0;
00650                 }
00651         }
00652         return -1;
00653 }
00654 
00655 int
00656 main(int argc, char *argv[])
00657 {
00658         int i, tn, menu=1;
00659 
00660         if (argc > 1) {
00661                 for (i=1; i<argc; i++) {
00662                         dotest(atoi(argv[i]));
00663                 }
00664                 return 0;
00665         }
00666 
00667         while (1) {
00668                 if (menu) {
00669                         for (i=0; tests[i].num>=0; i++) {
00670                                 printf("  %2d  %s\n", tests[i].num, 
00671                                        tests[i].desc);
00672                         }
00673                         menu = 0;
00674                 }
00675                 printf("malloctest: ");
00676                 tn = geti();
00677                 if (tn < 0) {
00678                         break;
00679                 }
00680 
00681                 if (dotest(tn)) {
00682                         menu = 1;
00683                 }
00684         }
00685 
00686         return 0;
00687 }
00688 
 All Data Structures