C:/Users/Dennis/src/lang/russell.orig/src/gc/test.c

Go to the documentation of this file.
00001 /* An incomplete test for the garbage collector.                */
00002 /* Some more obscure entry points are not tested at all.        */
00003 # include <stdlib.h>
00004 # include <stdio.h>
00005 # include "gc.h"
00006 # ifdef PCR
00007 #   include "th/PCR_ThCrSec.h"
00008 #   include "th/PCR_Th.h"
00009 # endif
00010 
00011 /* AT_END may be defined to excercise the interior pointer test */
00012 /* if the collector is configured with ALL_INTERIOR_POINTERS.   */
00013 /* As it stands, this test should succeed with either           */
00014 /* configuration.  In the FIND_LEAK configuration, it should    */
00015 /* find lots of leaks, since we free almost nothing.            */
00016 
00017 struct SEXPR {
00018     struct SEXPR * sexpr_car;
00019     struct SEXPR * sexpr_cdr;
00020 };
00021 
00022 # ifdef __STDC__
00023     typedef void * void_star;
00024 # else
00025     typedef char * void_star;
00026 # endif
00027 
00028 typedef struct SEXPR * sexpr;
00029 
00030 extern sexpr cons();
00031 
00032 # define nil ((sexpr) 0)
00033 # define car(x) ((x) -> sexpr_car)
00034 # define cdr(x) ((x) -> sexpr_cdr)
00035 # define is_nil(x) ((x) == nil)
00036 
00037 
00038 int extra_count = 0;        /* Amount of space wasted in cons node */
00039 
00040 /* Silly implementation of Lisp cons. Intentionally wastes lots of space */
00041 /* to test collector.                                                    */
00042 sexpr cons (x, y)
00043 sexpr x;
00044 sexpr y;
00045 {
00046     register sexpr r;
00047     register int *p;
00048     register my_extra = extra_count;
00049     
00050     r = (sexpr) GC_MALLOC(sizeof(struct SEXPR) + my_extra);
00051     if (r == 0) {
00052         (void)printf("Out of memory\n");
00053         exit(1);
00054     }
00055     for (p = (int *)r;
00056          ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
00057         if (*p) {
00058             (void)printf("Found nonzero at %X\n - allocator is broken", p);
00059             exit(1);
00060         }
00061         *p = 13;
00062     }
00063 #   ifdef AT_END
00064         r = (sexpr)((char *)r + (my_extra & ~7));
00065 #   endif
00066     r -> sexpr_car = x;
00067     r -> sexpr_cdr = y;
00068     extra_count = (my_extra + 1) % 5000;
00069     return(r);
00070 }
00071 
00072 /* Return reverse(x) concatenated with y */
00073 sexpr reverse1(x, y)
00074 sexpr x, y;
00075 {
00076     if (is_nil(x)) {
00077         return(y);
00078     } else {
00079         return( reverse1(cdr(x), cons(car(x), y)) );
00080     }
00081 }
00082 
00083 sexpr reverse(x)
00084 sexpr x;
00085 {
00086     return( reverse1(x, nil) );
00087 }
00088 
00089 sexpr ints(low, up)
00090 int low, up;
00091 {
00092     if (low > up) {
00093         return(nil);
00094     } else {
00095         return(cons((sexpr)low, ints(low+1, up)));
00096     }
00097 }
00098 
00099 void check_ints(list, low, up)
00100 sexpr list;
00101 int low, up;
00102 {
00103     if ((int)(car(list)) != low) {
00104         (void)printf(
00105            "List reversal produced incorrect list - collector is broken\n");
00106         exit(1);
00107     }
00108     if (low == up) {
00109         if (cdr(list) != nil) {
00110            (void)printf("List too long - collector is broken\n");
00111            exit(1);
00112         }
00113     } else {
00114         check_ints(cdr(list), low+1, up);
00115     }
00116 }
00117 
00118 /* Not used, but useful for debugging: */
00119 void print_int_list(x)
00120 sexpr x;
00121 {
00122     if (is_nil(x)) {
00123         (void)printf("NIL\n");
00124     } else {
00125         (void)printf("%d", car(x));
00126         if (!is_nil(cdr(x))) {
00127             (void)printf(", ");
00128             (void)print_int_list(cdr(x));
00129         } else {
00130             (void)printf("\n");
00131         }
00132     }
00133 }
00134 
00135 /* Try to force a to be strangely aligned */
00136 struct {
00137   char dummy;
00138   sexpr aa;
00139 } A;
00140 #define a A.aa
00141 
00142 /*
00143  * Repeatedly reverse lists built out of very different sized cons cells.
00144  * Check that we didn't lose anything.
00145  */
00146 reverse_test()
00147 {
00148     int i;
00149     sexpr b;
00150 
00151     a = ints(1, 100);
00152     b = ints(1, 50);
00153     for (i = 0; i < 50; i++) {
00154         b = reverse(reverse(b));
00155     }
00156     for (i = 0; i < 10; i++) {
00157         /* This maintains the invariant that a always points to a list of */
00158         /* 100 integers.  Thus this is thread safe without locks.         */
00159         a = reverse(reverse(a));
00160 #       if !defined(AT_END) && !defined(PCR)
00161           /* This is not thread safe, since realloc explicitly deallocates */
00162           if (i & 1) {
00163             a = (sexpr)GC_REALLOC((void_star)a, 500);
00164           } else {
00165             a = (sexpr)GC_REALLOC((void_star)a, 4200);
00166           }
00167 #       endif
00168     }
00169     check_ints(a,1,100);
00170     check_ints(b,1,50);
00171     a = b = 0;
00172 }
00173 
00174 /*
00175  * The rest of this builds balanced binary trees, checks that they don't
00176  * disappear, and tests finalization.
00177  */
00178 typedef struct treenode {
00179     int level;
00180     struct treenode * lchild;
00181     struct treenode * rchild;
00182 } tn;
00183 
00184 int finalizable_count = 0;
00185 int finalized_count = 0;
00186 int dropped_something = 0;
00187 
00188 # ifdef __STDC__
00189   void finalizer(void * obj, void * client_data)
00190 # else
00191   void finalizer(obj, client_data)
00192   char * obj;
00193   char * client_data;
00194 # endif
00195 {
00196   tn * t = (tn *)obj;
00197   if ((int)client_data != t -> level) {
00198      (void)printf("Wrong finalization data - collector is broken\n");
00199      exit(1);
00200   }
00201   finalized_count++;
00202 }
00203 
00204 size_t counter = 0;
00205 
00206 tn * mktree(n)
00207 int n;
00208 {
00209     tn * result = (tn *)GC_MALLOC(sizeof(tn));
00210     
00211     if (n == 0) return(0);
00212     if (result == 0) {
00213         (void)printf("Out of memory\n");
00214         exit(1);
00215     }
00216     result -> level = n;
00217     result -> lchild = mktree(n-1);
00218     result -> rchild = mktree(n-1);
00219     if (counter++ % 119 == 0) {
00220         GC_REGISTER_FINALIZER((void_star)result, finalizer, (void_star)n,
00221                               (GC_finalization_proc *)0, (void_star *)0);
00222 #       ifdef PCR
00223             PCR_ThCrSec_EnterSys();
00224             /* Losing a count here causes erroneous report of failure. */
00225 #       endif
00226         finalizable_count++;
00227 #       ifdef PCR
00228             PCR_ThCrSec_ExitSys();
00229 #       endif
00230     }
00231     return(result);
00232 }
00233 
00234 void chktree(t,n)
00235 tn *t;
00236 int n;
00237 {
00238     if (n == 0 && t != 0) {
00239         (void)printf("Clobbered a leaf - collector is broken\n");
00240         exit(1);
00241     }
00242     if (n == 0) return;
00243     if (t -> level != n) {
00244         (void)printf("Lost a node at level %d - collector is broken\n", n);
00245         exit(1);
00246     }
00247     if (counter++ % 373 == 0) (void) GC_MALLOC(counter%5001);
00248     chktree(t -> lchild, n-1);
00249     if (counter++ % 73 == 0) (void) GC_MALLOC(counter%373);
00250     chktree(t -> rchild, n-1);
00251 }
00252 
00253 void alloc_small(n)
00254 int n;
00255 {
00256     register int i;
00257     
00258     for (i = 0; i < n; i += 8) {
00259         if (GC_MALLOC_ATOMIC(8) == 0) {
00260             (void)printf("Out of memory\n");
00261             exit(1);
00262         }
00263     }
00264 }
00265 
00266 tree_test()
00267 {
00268     tn * root = mktree(16);
00269     register int i;
00270     
00271     alloc_small(5000000);
00272     chktree(root, 16);
00273     if (finalized_count && ! dropped_something) {
00274         (void)printf("Premature finalization - collector is broken\n");
00275         exit(1);
00276     }
00277     dropped_something = 1;
00278     root = mktree(16);
00279     chktree(root, 16);
00280     for (i = 16; i >= 0; i--) {
00281         root = mktree(i);
00282         chktree(root, i);
00283     }
00284     alloc_small(5000000);
00285 }
00286 
00287 # include "gc_private.h"
00288 
00289 int n_tests = 0;
00290 
00291 void run_one_test()
00292 {
00293     DCL_LOCK_STATE;
00294     
00295     reverse_test();
00296     tree_test();
00297     LOCK();
00298     n_tests++;
00299     UNLOCK();
00300     
00301 }
00302 
00303 void check_heap_stats()
00304 {
00305     (void)printf("Completed %d tests\n", n_tests);
00306     (void)printf("Finalized %d/%d objects - ",
00307                  finalized_count, finalizable_count);
00308     if (finalized_count > finalizable_count
00309         || finalized_count < finalizable_count/2) {
00310         (void)printf ("finalization is probably broken\n");
00311         exit(1);
00312     } else {
00313         (void)printf ("finalization is probably ok\n");
00314     }
00315     (void)printf("Total number of bytes allocated is %d\n",
00316                  WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc));
00317     (void)printf("Final heap size is %d bytes\n", GC_heapsize);
00318     if (WORDS_TO_BYTES(GC_words_allocd + GC_words_allocd_before_gc)
00319         < 33500000*n_tests) {
00320         (void)printf("Incorrect execution - missed some allocations\n");
00321         exit(1);
00322     }
00323     if (GC_heapsize > 10000000*n_tests) {
00324         (void)printf("Unexpected heap growth - collector may be broken\n");
00325         exit(1);
00326     }
00327     (void)printf("Collector appears to work\n");
00328 }
00329 
00330 #ifndef PCR
00331 main()
00332 {
00333     n_tests = 0;
00334     run_one_test();
00335     check_heap_stats();
00336     (void)fflush(stdout);
00337     return(0);
00338 }
00339 # else
00340 test()
00341 {
00342     PCR_Th_T * th1;
00343     PCR_Th_T * th2;
00344     int code;
00345 
00346     n_tests = 0;
00347     th1 = PCR_Th_Fork(run_one_test, 0);
00348     th2 = PCR_Th_Fork(run_one_test, 0);
00349     run_one_test();
00350     if (PCR_Th_T_Join(th1, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
00351         != PCR_ERes_okay || code != 0) {
00352         (void)printf("Thread 1 failed\n");
00353     }
00354     if (PCR_Th_T_Join(th2, &code, NIL, PCR_allSigsBlocked, PCR_waitForever)
00355         != PCR_ERes_okay || code != 0) {
00356         (void)printf("Thread 2 failed\n");
00357     }
00358     check_heap_stats();
00359     (void)fflush(stdout);
00360     return(0);
00361 }
00362 #endif
00363 

Generated on Fri Jan 25 10:39:46 2008 for russell by  doxygen 1.5.4