home *** CD-ROM | disk | FTP | other *** search
- /*
- * Plurals
- *
- * Author: S.C.Merrall
- *
- * File: mp_gc.m
- *
- * Contents: heap_alloc
- * mp_alloc
- * test
- * eq
- * copy
- * mp_gc
- * gc
- *
- * Description: Allocation and garbage collection of heap objects
- * works with the same memory as mp_mem_mgmt uses but
- * the garbage collection processes are different.
- *
- * Change History:
- *
- * Date Name Comment
- * -------- ---- -------
- * 16:04:91 SCM Created
- * 22:04:91 SCM Uses MasPar Plural Heap objects instead of offsets
- * 15:05:91 SCM heap_alloc takes space as multiple of 16-bits not 32
- * 16:06:91 SCM mp_alloc transferred from mp_alloc.m
- * 04:06:91 SCM Sizes in bytes, plus alignment
- * 26:01:92 SCM Added some GC code
- * 02:02:92 SCM Made eq work properly and cope with symbols
- * 06:04:92 SCM Clever hack for nullp in test wont work as NIL changed
- *
- */
-
- #include <mpl.h>
- #include <stdio.h>
-
- #include "proc_pair.h"
-
- #include "constant.h"
-
- #include "mp_utils.h"
- #include "mp_object.h"
- #include "mp_debug_off.h"
- #include "mp_mem_mgmt.h"
- #include "mp_type.h"
- #include "mp_gc.h"
-
- #define SDEBUG(x) DO_DEBUG(x)
-
- char *gc_message; /* Used to indicate what function caused the GC */
-
- plural natural *gc_roots[MAX_GC_ROOTS+1];
- int next_gc_root = 0;
-
- /* Scratch Space: same ammount of memory on each processor, used for message
- * passing and printing */
-
- char acu_scratch[SCRATCH_MEMORY_SIZE];
- visible plural char scratch[SCRATCH_MEMORY_SIZE];
-
- /* This array contains the size of a given object under its identifier */
-
- #define TYPE_SIZE 0
- #define TYPE_ALIGN 1
-
- int type_info_table[NUMBER_OF_TYPES][2] = { NULL, NULL,
- INTEGER_SIZE, INTEGER_ALIGN,
- MP_CONS_SIZE, MP_CONS_ALIGN,
- MP_VECTOR_SIZE, MP_VECTOR_ALIGN,
- MP_FLOAT_SIZE, MP_FLOAT_ALIGN,
- MP_SYMBOL_SIZE, MP_SYMBOL_ALIGN};
- /*
- * Each processors heap space can be grabage collected by mark and sweep
- * the marking is done by tracing through the heap space from the pointers
- * in the plural space. Garbage collection will be fired when heap_alloc
- * fails, if GC fails to claim sufficient space, a global garbage collection
- * can be forced and another local garbage collection attempted. If that fails
- * to a reorganisation of the array may be able to make space available
- */
-
- /*----------------------------------------------------------------------------*
- * Function : heap_alloc
- *
- * Parameters : plural int space: How much memory we want
- * allocated on each active
- * processor. (in bytes)
- * plural int type: the types of the things
- * were allocating space for
- * MP_PluralHeap MPPH_var: MP_PluralHeap object, handle
- * the plural heap objects.
- *
- * Description: Allocates the requested ammount of memory on each active
- * processor. If one processor fails the whole operation fails.
- * The allocated space is aligned if appropriate, this may
- * cause gaps in the heap, these are filled with null objects
- * of the appropriate size.
- *
- * Result : int: SUCCESS/FAIL
- *---------------------------------------------------------------------------*/
-
- #ifdef __STDC__
-
- int heap_alloc( plural int space, plural int type, MP_PluralHeap MPPH_var )
-
- #else
-
- int heap_alloc( space, type, MPPH_var )
-
- plural int space;
- plural int type;
- MP_PluralHeap MPPH_var;
-
- #endif
-
- {
- plural heap_header header;
- plural int new_heap_space;
- plural int align;
- DBG_CALL("heap_alloc");
- DBG_ARGS(fprintf(dbg,"space=????, type=????, MPPH_var=%04x: to_offsets=%04x",MPPH_var,OA_to_offsets(MPPH_var)));
-
- align = type_info_table[type][TYPE_ALIGN];
-
- new_heap_space = heap_space + 1;
- new_heap_space = new_heap_space +
- (((new_heap_space * sizeof(natural)) % align) / sizeof(natural));
-
- /* new_heap_space is the location where the aligned data will begin */
- /* the header will be placed in the previous location, */
-
- if (globalor((plural_space - heap2plural(new_heap_space)) <=
- heap2plural(byte2heap(space)+2))) {
-
- fprintf(stderr,"mp_alloc:No Space, trying back end GC\n");
- mp_gc();
- new_heap_space = heap_space + 1;
- new_heap_space = new_heap_space +
- (((new_heap_space * sizeof(natural)) % align) / sizeof(natural));
-
- if (globalor((plural_space - heap2plural(new_heap_space)) <=
- heap2plural(byte2heap(space)))) {
-
- DBG_FAIL(fprintf(dbg,"FAIL:No Space; p_space=%d, ",plural_space);DBG_PARG("h_space","%04d ",heap_space));
- return FAIL;
- }
- }
-
- /* Initialise header data, store heap offsets for caller,update heap space */
-
- *MPPH_var = new_heap_space-1;
-
- HH_set_space(heap_memory[*MPPH_var],space);
- HH_set_free(heap_memory[*MPPH_var],0);
- HH_set_info(heap_memory[*MPPH_var],type);
- heap_space = new_heap_space + MP_LENGTH(OA_space(MPPH_var));
-
- DBG_EXIT(fprintf(dbg,"SUCCESS"));
- return SUCCESS;
- }
-
- /*----------------------------------------------------------------------------*
- * Function : mp_alloc
- *
- * Parameters : plural int type: The types of the objects to be
- * allocated.
- * plural int quantity: This is for giving vector size.
- * MP_PluralHeap MPPH_object: MP_PluralHeap object, handle
- * on the allocated plural heap space.
- *
- * Description: Allocates different types and sizes of objects in
- * parallel and initialises them all to nil.
- *
- * Result : int: FAIL/SUCCESS
- *---------------------------------------------------------------------------*/
-
- #ifdef __STDC__
-
- int mp_alloc( plural int type, plural int quantity, MP_PluralHeap MPPH_object )
-
- #else
-
- int mp_alloc( type, quantity, MPPH_object )
-
- plural int type;
- plural int quantity;
- MP_PluralHeap MPPH_object;
-
- #endif
-
- {
- plural int size;
- plural natural *plural space;
- plural int i;
- DBG_CALL("mp_alloc");
- DBG_ARGS(fprintf(dbg,"type=????,quantity=????,MPPH_object=%04x",MPPH_object));
-
- /* Find sizes of objects being requested */
- /* NOTE: this should be done via a table to reduce code length */
-
- if (globalor((type <= 0) || (type >= NUMBER_OF_TYPES))) {
-
- DBG_FAIL(fprintf(dbg,"FAIL: Unknown types"));
- return FAIL;
- }
-
- size = type_info_table[type][TYPE_SIZE];
-
- /* Allocate space for new objects */
-
- if (heap_alloc((quantity * size), type, MPPH_object) == FAIL) {
-
- DBG_FAIL(fprintf(dbg,"FAIL: Unable to allocate space"));
- return FAIL;
- }
-
- DBG_EXIT(fprintf(dbg,"SUCCESS"));
- return SUCCESS;
- }
-
- /*----------------------------------------------------------------------------*
- * Function : test
- *
- * Parameters : MP_PluralHeap MPPH_arg1: Heap objects to test types of
- * plural int type: Types we are expecting
- * MP_PluralHeap MPPH_result: Boolean result
- *
- * Description: Returns booleans indicating wether the objects are of the
- * type indicated by type.
- *
- * Result : int FAIL/SUCCESS
- *---------------------------------------------------------------------------*/
-
- #ifdef __STDC__
-
- int test( MP_PluralHeap MPPH_arg1, plural int type, MP_PluralHeap MPPH_result )
-
- #else
-
- int test( MPPH_arg1, type, MPPH_result )
-
- MP_PluralHeap MPPH_arg1;
- plural int type;
- MP_PluralHeap MPPH_result;
-
- #endif
-
- {
- plural int boolean;
- DBG_CALL("test");
- DBG_ARGS(fprintf(dbg,"MPPH_arg1=????, type=????, MPPH_result=????"));
-
- /* if (OA_offsets(MPPH_arg1) == NIL) {
- *
- * boolean = (NIL == type);
- * }
- * else {
- * Can't tell if it's null by looking at the type and addresss since the
- * values overlap now
- */
-
- boolean = OA_info(MPPH_arg1) == type;
-
- if (boolean) OA_offsets(MPPH_result) = NOT_NIL;
- else OA_offsets(MPPH_result) = NIL;
-
- DBG_EXIT(fprintf(dbg,"SUCCESS"));
- return SUCCESS;
- }
-
- /*----------------------------------------------------------------------------*
- * Function : eq
- *
- * Parameters : MP_PluralHeap MPPH_arg1: Handle on plural space of
- * MP_PluralHeap MPPH_arg2: objects to be compared
- * MP_PluralHeap MPPH_result: Plural space containing
- * resulting boolean values.
- *
- * Description: Compares the objects on the same processors and creates
- * a boolean result.
- * Integers and floats are equal if their values are the same
- * otherwise if the addresses are equal the objects are equal -
- * This will need extending when symbols and doubles are added.
- *
- * Result : int: FAIL/SUCCESS
- *---------------------------------------------------------------------------*/
-
- #ifdef __STDC__
-
- int eq( MP_PluralHeap MPPH_arg1, MP_PluralHeap MPPH_arg2,
- MP_PluralHeap MPPH_result )
-
- #else
-
- int eq( MPPH_arg1, MPPH_arg2, MPPH_result )
-
- MP_PluralHeap MPPH_arg1;
- MP_PluralHeap MPPH_arg2;
- MP_PluralHeap MPPH_result;
-
- #endif
-
- {
- plural int *plural result;
- DBG_CALL("eq");
- DBG_ARGS(fprintf(dbg,"MPPH_arg1=????, MPPH_arg2=????, MPPH_arg3=????"));
-
- OA_offsets(MPPH_result) = NIL;
-
- if (OA_offsets(MPPH_arg1) == OA_offsets(MPPH_arg2)) {
-
- OA_offsets(MPPH_result) = NOT_NIL;
- }
-
- else if ((OA_offsets(MPPH_arg1)==NIL)||(OA_offsets(MPPH_arg1)==NOT_NIL) ||
- (OA_offsets(MPPH_arg2)==NIL)||(OA_offsets(MPPH_arg2)==NOT_NIL)) {
-
- OA_offsets(MPPH_result) = NIL;
- }
- else if (OA_info(MPPH_arg1) != OA_info(MPPH_arg2)) {
-
- OA_offsets(MPPH_result) = NIL;
- }
- else if ((OA_info(MPPH_arg1) == INTEGER) ||
- (OA_info(MPPH_arg1) == MP_SYMBOL)) {
-
- /* Just compare the bit patterns in affect */
-
- if ((*(plural int *plural) OA_data(MPPH_arg1)) ==
- (*(plural int *plural) OA_data(MPPH_arg2)))
- OA_offsets(MPPH_result) = NOT_NIL;
- }
-
- DBG_EXIT(fprintf(dbg,"SUCCESS"));
- return SUCCESS;
- }
-
- /* Garbage Collection Rational
- * ======= ========== ========
- *
- * The current garbage collector is designed to work on the back end only,
- * there is no need to worry about pointers to the front end as currenmtly
- * they cannot be constructed.
- * The idea is to half the number of processors and to perform a stop and
- * copy operation form one processor set to the idle set and to then resume
- * processing on the alternative set. To do this the code must all work in
- * terms of the Paired Processor macros (see proc_pair.h).
- *
- */
-
-
- /*----------------------------------------------------------------------------*
- * Function : gc
- *
- * Parameters : MP_PluralHeap MPPH_objects: This is a parallel lisp object
- * to be (recursively) copied
- * to the alternative processor
- * set
- *
- * Description: What the function does should go here. The problem of
- * justification
- *
- * Result : MP_PluralHeap: the new position of the objects
- *---------------------------------------------------------------------------*/
-
- #ifdef __STDC__
-
- plural natural gc( plural natural offsets )
-
- #else
-
- plural natural gc( offsets )
-
- plural natural offsets;
-
- #endif
-
- {
- plural natural *plural general_vector;
- plural natural size, align;
- plural natural result_offset;
- plural heap_header headers;
- plural heap_header data;
- plural natural this_heap_space;
- plural int i;
- DBG_CALL("gc");
- DBG_ARGS(DBG_PARG("PP_iproc","%d ",PP_iproc);DBG_PARG(" \noffsets","%d ",offsets));
-
- /* The active set on entry to the function will be pairs of processors,
- * that is for each gcing processor which is active, its associated
- * pair-processor is also active.
- */
-
- PP_on_set() PP_push_to(offsets, offsets);
-
- if ((offsets == NIL) || (offsets == NOT_NIL)) {
-
- result_offset = offsets; /* These special objects */
- DBG_EXIT(DBG_PARG("","%d ",result_offset));
- return result_offset; /* are represented by a
- * special offset, so we
- * merely copy this offset
- */
- }
-
- PP_on_set() {
-
- headers = heap_memory[offsets]; /* get headers */
- PP_push_to(headers, headers); /* duplicate in paired PE
- * this will mean the PES
- * get activated in pairs
- */
- }
-
- if (HH_gced_p(headers)) { /* already gced the offset of the
- * object on the `off' PE is held
- * on the `on' PE in the header,
- * copy this offset
- */
-
- PP_on_set() PP_push_to(result_offset, HH_gcto(headers));
- DEBUG(DBG_PARG("Extracted forward address","%d ",headers));
- DBG_EXIT(DBG_PARG("","%d ",result_offset));
- return result_offset;
- }
-
- /* PP_off_set() {
- *
- * result_offset = heap_space;
- * PP_push_to(result_offset, result_offset);
- * heap_memory[heap_space++] = headers;
- * }
- * PP_on_set() HH_gc_moved(heap_memory[offsets],result_offset);
- */
-
- /* Deal with the header: Increament heap_space, it now is the position where
- * the data starts and the header goes in the previous slot. munge the heap
- * space to allow for alignment if required. result_offset, is where the
- * header is (i.e. heap_space - 1) and we leave the forwarding address
- */
-
- PP_off_set() ++heap_space;
-
- switch (HH_info(headers)) {
-
- case MP_SYMBOL:
- case MP_FLOAT:
- case INTEGER:
-
- align = type_info_table[HH_info(headers)][TYPE_ALIGN];
- PP_off_set() heap_space = heap_space +(((heap_space * sizeof(natural)) %
- align) / sizeof(natural));
- default:
-
- PP_off_set() heap_memory[(result_offset = heap_space-1)] = headers;
-
- PP_on_set() {
-
- PP_pull_to(result_offset,result_offset);
- HH_gc_moved(heap_memory[offsets],result_offset);
- }
- }
-
- switch (HH_info(headers)) {
-
- case MP_SYMBOL:
- case MP_FLOAT : /* Just copy the 4-byte bit pattern across */
- case INTEGER :
-
- size = MP_LENGTH(type_info_table[HH_info(headers)][TYPE_SIZE]);
-
- for (i=1; i<=size; i++) { /* We have to swap between active sets since
- * an operation has to be preformed on both
- * PEs as well as the Xnet assignment
- */
-
- PP_on_set() data = heap_memory[offsets + i];
- PP_off_set() PP_pull_to(heap_memory[heap_space++],data);
- }
- break;
-
- case MP_VECTOR : /* These contain objects so we have to */
- case MP_CONS : /* call gc again to copy them
- * across. The result is the new address
- * in the `off' set of PEs.
- */
-
- size = MP_LENGTH(HH_space(headers)); /* reserve space for object */
- PP_off_set() heap_space=heap_space+size;
- general_vector = (plural natural *plural) (heap_memory + offsets + 1);
-
- for (i = 0; i<size; i++) { /* Note: Pairs of active processors still */
-
- data = (plural heap_header) gc(general_vector[i]);
- PP_off_set() heap_memory[result_offset+i+1]=data;
- }
- break;
- }
-
- DBG_EXIT(DBG_PARG("","%d ",result_offset));
- return result_offset;
- }
-
- /*----------------------------------------------------------------------------*
- * Function : mp_gc
- *
- * Parameters : none
- *
- * Description: Garbage collects the system, this involves following all the
- * heap roots in the plural space and copying them to the
- * `off' processor set. The active memory will be contiguous
- * and garbage will have been lost. The `off' set becomes the
- * `on' set.
- *
- * Result : void
- *---------------------------------------------------------------------------*/
-
- #ifdef __STDC__
-
- visible void mp_gc( void )
-
- #else
-
- visible void mp_gc( )
-
- #endif
-
- {
- int i;
- plural int retrieved;
- plural natural new_offsets;
- plural natural gc_root;
- int old_debug_status=debug_status;
- DBG_CALL("mp_gc");
- DBG_ARGS(fprintf(dbg,"void"));
-
- PP_on_set() retrieved = heap_space;
-
- DBG_OFF();
- all {
-
- PP_off_set() heap_space = NOT_NIL + MP_LENGTH(sizeof(heap_header) +
- type_info_table[MP_SYMBOL][TYPE_SIZE]);
-
- for (i = TOP; i>plural_space; i--) {
-
- /* First copy the data across, if this is not actually a pointer we need
- * to do this any way. It also means we can activate the processors in
- * pairs when we examine the contents of the slot. This is necessary for
- * the calls to gc.
- */
-
- PP_on_set() PP_push_to(plural_memory[i],plural_memory[i]);
-
- if (!(plural_memory[i] & FREE_FLAG)) { /* Not free memory so gc it. The
- * value of gc for the `off'
- * set is where the `on' objects
- * were copied to. The `on'
- * value is not important.
- */
-
- plural_memory[i] = gc( plural_memory[i] );
- }
- }
-
- /* Because we may have gced in the middle of doing something we may have
- * handles on heap stuff which are not reachable from the plural space.
- * We instigate a gc for each of the varibales on the gc protect stack
- */
-
- fprintf(stderr,"mp_gc debug: %d gc protect roots\n",next_gc_root);
-
- for (i=0;i<next_gc_root;i++) {
-
- gc_root = *gc_roots[i];
- PP_on_set() PP_push_to(gc_root,gc_root);
- if (!(gc_root & FREE_FLAG)) gc_root = gc( gc_root );
- PP_on_set() PP_pull_to(gc_root,gc_root);
- *gc_roots[i] = gc_root;
- }
-
- /* Now we have to copy the gumpf back, the starting active set is
- * the even processors so we are copying from the offset, leftwards
- */
-
- PP_off_set() {
-
- pp_xsend(0,-1,(plural char *plural) heap_memory,
- (plural char *plural) heap_memory, MEMORY_SIZE_IN_BYTES);
- PP_push_to(heap_space,heap_space);
- }
- }
- debug_status=old_debug_status;
-
-
- /* Some More Debugging Info */
-
- PP_on_set() {
-
- retrieved = retrieved - heap_space;
- fprintf(stderr,"Top-Level=%s, some stats:\n",gc_message);
- DBG_PVAR(stderr,"Retrieved","%04d ",retrieved);
- DBG_PVAR(stderr,"\nHeap Top ","%04d ",heap_space);
- fprintf(stderr,"\n");
- }
- DBG_OFF();
- DBG_EXIT(fprintf(dbg,"void"));
- }
-
-
-
-
-