changeset 50:8f7141a9272e

Added VMS__malloc and probes, and major re-factoring to separate mallocs
author Me
date Sat, 30 Oct 2010 20:54:36 -0700
parents 5388f1c2da6f
children 2952d337d6f3
files CoreLoop.c MasterLoop.c VMS.c VMS.h probes.c probes.h vmalloc.c vmalloc.h
diffstat 8 files changed, 1188 insertions(+), 243 deletions(-) [+]
line diff
     1.1 --- a/CoreLoop.c	Thu Oct 14 17:07:23 2010 -0700
     1.2 +++ b/CoreLoop.c	Sat Oct 30 20:54:36 2010 -0700
     1.3 @@ -83,11 +83,14 @@
     1.4  CoreLoopStartPt:
     1.5     
     1.6        //Get virtual processor from queue
     1.7 -      //_VMSWorkQ must be a global, static volatile var, so not kept in reg,
     1.8 +      //The Q must be a global, static volatile var, so not kept in reg,
     1.9        // which forces reloading the pointer after each jmp to this point
    1.10     readyToAnimateQ  = _VMSMasterEnv->readyToAnimateQs[thisCoresIdx];
    1.11  
    1.12     currPr = (VirtProcr *) readSRSWQ_NonBlocking( readyToAnimateQ );
    1.13 +   
    1.14 +   if( currPr != NULL ) _VMSMasterEnv->numMasterInARow[thisCoresIdx] = 0;
    1.15 +
    1.16     int tries = 0; int gotLock = 0;
    1.17     while( currPr == NULL )
    1.18      {    //no VPs ready to animate, so run MasterVP --later make "try Master"
    1.19 @@ -101,24 +104,20 @@
    1.20           //check if get the MasterLock
    1.21        gotLock = __sync_bool_compare_and_swap( &(_VMSMasterEnv->masterLock), \
    1.22                                                   UNLOCKED, LOCKED );
    1.23 -
    1.24        if( gotLock )
    1.25 -       {
    1.26 -            //run own MasterVP -- when its done, unlocks MasterLock and
    1.27 +       {    //run own MasterVP -- when its done, unlocks MasterLock and
    1.28              // jumps back to coreLoops's startPt
    1.29           currPr = _VMSMasterEnv->masterVPs[thisCoresIdx];
    1.30 +         if( _VMSMasterEnv->numMasterInARow[thisCoresIdx] > 10000 )
    1.31 +            printf("10000 back to back MasterVP\n");
    1.32 +         _VMSMasterEnv->numMasterInARow[thisCoresIdx] += 1;
    1.33           break;  //end while -- have a VP to animate now
    1.34         }
    1.35 -         //Aug 24, 2010 -- changed so each core loop only gets work scheduled
    1.36 -         // by its own master, so now stay in loop until get lock
    1.37 -//      currPr = (VirtProcr *) readSRSWQ_NonBlocking( readyToAnimateQ );
    1.38        
    1.39        tries++;
    1.40 -//      if( tries % 10000 == 0 ) printf("empty tries: %d\n", tries/10000 );
    1.41 -      if( tries % READYTOANIMATE_RETRIES == 0 ) pthread_yield();
    1.42 +      if( tries > READYTOANIMATE_RETRIES ) { tries = 0; pthread_yield(); }
    1.43      }
    1.44     
    1.45 -//   currPr->coreAnimatedBy  = coreLoopThdParams->coreNum;
    1.46  
    1.47        //switch to virt procr's stack and frame ptr then jump to virt procr fn
    1.48     void *stackPtr, *framePtr, *jmpPt, *coreLoopFramePtrAddr, \
    1.49 @@ -205,11 +204,17 @@
    1.50     readyToAnimateQ  = _VMSMasterEnv->readyToAnimateQs[thisCoresIdx];
    1.51     currPr = (VirtProcr *) readSRSWQ_NonBlocking( readyToAnimateQ );
    1.52     if( currPr == NULL )
    1.53 +    { if( _VMSMasterEnv->numMasterInARow[thisCoresIdx] )
    1.54 +         printf("back to back MasterVP\n");
    1.55 +      _VMSMasterEnv->numMasterInARow[thisCoresIdx] = TRUE;
    1.56        currPr = _VMSMasterEnv->masterVPs[thisCoresIdx];
    1.57 -   
    1.58 +    }
    1.59 +   else
    1.60 +    _VMSMasterEnv->numMasterInARow[thisCoresIdx] = FALSE;
    1.61  
    1.62 -//   printf("core %d loop procr addr: %d\n", coreLoopThdParams->coreNum, \
    1.63 -//       (int)currPr ); fflush(stdin);
    1.64 +         PRINT2_DEBUG("core %d loop procr addr: %d\n",\
    1.65 +                       coreLoopThdParams->coreNum,    \
    1.66 +                       (int)currPr )
    1.67  
    1.68        //switch to virt procr's stack and frame ptr then jump to virt procr
    1.69     void *stackPtr, *framePtr, *jmpPt, *coreLoopFramePtrAddr, \
     2.1 --- a/MasterLoop.c	Thu Oct 14 17:07:23 2010 -0700
     2.2 +++ b/MasterLoop.c	Sat Oct 30 20:54:36 2010 -0700
     2.3 @@ -185,4 +185,3 @@
     2.4                  );//can probably make clobber list empty -- but safe for now
     2.5   }
     2.6  
     2.7 -
     3.1 --- a/VMS.c	Thu Oct 14 17:07:23 2010 -0700
     3.2 +++ b/VMS.c	Sat Oct 30 20:54:36 2010 -0700
     3.3 @@ -6,7 +6,9 @@
     3.4  
     3.5  #include <stdio.h>
     3.6  #include <stdlib.h>
     3.7 +#include <string.h>
     3.8  #include <malloc.h>
     3.9 +#include <sys/time.h>
    3.10  
    3.11  #include "VMS.h"
    3.12  #include "Queue_impl/BlockingQueue.h"
    3.13 @@ -28,6 +30,10 @@
    3.14  void
    3.15  create_the_coreLoop_OS_threads();
    3.16  
    3.17 +MallocProlog *
    3.18 +create_free_list();
    3.19 +
    3.20 +
    3.21  pthread_mutex_t suspendLock = PTHREAD_MUTEX_INITIALIZER;
    3.22  pthread_cond_t  suspend_cond  = PTHREAD_COND_INITIALIZER;
    3.23  
    3.24 @@ -100,67 +106,47 @@
    3.25     allSchedSlots    = malloc( NUM_CORES * sizeof(SchedSlot *) );
    3.26  
    3.27     for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
    3.28 -    {
    3.29 +    {    //running in main thread -- normal malloc inside makeSRSWQ
    3.30        readyToAnimateQs[ coreIdx ] = makeSRSWQ();
    3.31        
    3.32 -         //Q: should give masterVP core-specific into as its init data?
    3.33 -      masterVPs[ coreIdx ] = VMS__create_procr( &masterLoop, masterEnv );
    3.34 +         //Q: should give masterVP core-specific info as its init data?
    3.35 +      masterVPs[ coreIdx ] = VMS_ext__create_procr( &masterLoop, masterEnv );
    3.36        masterVPs[ coreIdx ]->coreAnimatedBy = coreIdx;
    3.37        allSchedSlots[ coreIdx ] = create_sched_slots(); //makes for one core
    3.38 +      _VMSMasterEnv->numMasterInARow[ coreIdx ] = FALSE;
    3.39      }
    3.40     _VMSMasterEnv->readyToAnimateQs = readyToAnimateQs;
    3.41     _VMSMasterEnv->masterVPs        = masterVPs;
    3.42 +   _VMSMasterEnv->masterLock       = UNLOCKED;
    3.43     _VMSMasterEnv->allSchedSlots    = allSchedSlots;
    3.44 -
    3.45 +   _VMSMasterEnv->numProcrsCreated = 0;
    3.46  
    3.47  
    3.48        //Aug 19, 2010:  no longer need to place initial masterVP into queue
    3.49        // because coreLoop now controls -- animates its masterVP when no work
    3.50  
    3.51 +   _VMSMasterEnv->freeListHead        = VMS__create_free_list();
    3.52 +   _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
    3.53  
    3.54 -   //==================== malloc substitute ========================
    3.55 -   //
    3.56 -   //Testing whether malloc is using thread-local storage and therefore
    3.57 -   // causing unreliable behavior.
    3.58 -   //Just allocate a massive chunk of memory and roll own malloc/free and
    3.59 -   // make app use VMS__malloc_to, which will suspend and perform malloc
    3.60 -   // in the master, taking from this massive chunk.
    3.61 +   //============================= MEASUREMENT STUFF ========================
    3.62 +   #ifdef STATS__TURN_ON_PROBES
    3.63 +      //creates intervalProbes array and sets pointer to it in masterEnv too
    3.64 +   _VMSMasterEnv->dynIntervalProbesInfo =
    3.65 +                  makeDynArrayOfSize( &(_VMSMasterEnv->intervalProbes), 20 );
    3.66  
    3.67 -//   initFreeList();
    3.68 +   _VMSMasterEnv->probeNameHashTbl = makeHashTable( 1000, NULL );
    3.69 +   _VMSMasterEnv->masterCreateProbeID =
    3.70 +       VMS_ext__record_time_point_into_new_probe( "masterCreateProbe" );
    3.71 +      //Also put creation time directly into master env, for fast retrieval
    3.72 +   struct timeval timeStamp;
    3.73 +   gettimeofday( &(timeStamp), NULL);
    3.74 +   _VMSMasterEnv->createPtInSecs =
    3.75 +                           timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0);
    3.76 +   #endif
    3.77 +   //========================================================================
    3.78  
    3.79   }
    3.80  
    3.81 -/*
    3.82 -void
    3.83 -initMasterMalloc()
    3.84 - {
    3.85 -   _VMSMasterEnv->mallocChunk = malloc( MASSIVE_MALLOC_SIZE );
    3.86 -
    3.87 -      //The free-list element is the first several locations of an
    3.88 -      // allocated chunk -- the address given to the application is pre-
    3.89 -      // pended with both the ownership structure and the free-list struc.
    3.90 -      //So, write the values of these into the first locations of
    3.91 -      // mallocChunk -- which marks it as free & puts in its size.
    3.92 -   listElem = (FreeListElem *)_VMSMasterEnv->mallocChunk;
    3.93 -   listElem->size = MASSIVE_MALLOC_SIZE - NUM_PREPEND_BYTES
    3.94 -   listElem->next = NULL;
    3.95 - }
    3.96 -
    3.97 -void
    3.98 -dissipateMasterMalloc()
    3.99 - {
   3.100 -      //Just foo code -- to get going -- doing as if free list were link-list
   3.101 -   currElem = _VMSMasterEnv->freeList;
   3.102 -   while( currElem != NULL )
   3.103 -    {
   3.104 -      nextElem = currElem->next;
   3.105 -      masterFree( currElem );
   3.106 -      currElem = nextElem;
   3.107 -    }
   3.108 -   free( _VMSMasterEnv->freeList );
   3.109 - }
   3.110 - */
   3.111 -
   3.112  SchedSlot **
   3.113  create_sched_slots()
   3.114   { SchedSlot  **schedSlots;
   3.115 @@ -213,7 +199,7 @@
   3.116                          thdAttrs,
   3.117                         &coreLoop,
   3.118                 (void *)(coreLoopThdParams[coreIdx]) );
   3.119 -      if(retCode){printf("ERROR creating thread: %d\n", retCode); exit(0);}
   3.120 +      if(retCode){printf("ERROR creating thread: %d\n", retCode); exit(1);}
   3.121      }
   3.122   }
   3.123  
   3.124 @@ -225,12 +211,6 @@
   3.125  VMS__start_the_work_then_wait_until_done()
   3.126   { int coreIdx;
   3.127        //Start the core loops running
   3.128 -//===========================================================================
   3.129 -   TSCount  startCount, endCount;
   3.130 -   unsigned long long count = 0, freq = 0;
   3.131 -   double   runTime;
   3.132 -
   3.133 -      startCount = getTSCount();
   3.134     
   3.135        //tell the core loop threads that setup is complete
   3.136        //get lock, to lock out any threads still starting up -- they'll see
   3.137 @@ -251,14 +231,6 @@
   3.138        //NOTE: do not clean up VMS env here -- semantic layer has to have
   3.139        // a chance to clean up its environment first, then do a call to free
   3.140        // the Master env and rest of VMS locations
   3.141 -
   3.142 -
   3.143 -      endCount = getTSCount();
   3.144 -      count = endCount - startCount;
   3.145 -
   3.146 -      runTime = (double)count / (double)TSCOUNT_FREQ;
   3.147 -
   3.148 -      printf("\n Time startup to shutdown: %f\n", runTime); fflush( stdin );
   3.149   }
   3.150  
   3.151  /*Only difference between version with an OS thread pinned to each core and
   3.152 @@ -285,37 +257,73 @@
   3.153   * animator state to return to --
   3.154   *
   3.155   */
   3.156 -VirtProcr *
   3.157 -VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   3.158 - { VirtProcr *newPr;
   3.159 -   char      *stackLocs, *stackPtr;
   3.160 +inline VirtProcr *
   3.161 +create_procr_helper( VirtProcr *newPr,       VirtProcrFnPtr  fnPtr,
   3.162 +                     void      *initialData, char           *stackLocs )
   3.163 + {
   3.164 +   char  *stackPtr;
   3.165  
   3.166 -   newPr              = malloc( sizeof(VirtProcr) );
   3.167 -   newPr->procrID     = numProcrsCreated++;
   3.168 +   newPr->procrID     = _VMSMasterEnv->numProcrsCreated++;
   3.169     newPr->nextInstrPt = fnPtr;
   3.170     newPr->initialData = initialData;
   3.171     newPr->requests    = NULL;
   3.172     newPr->schedSlot   = NULL;
   3.173 -//   newPr->coreLoopStartPt = _VMSMasterEnv->coreLoopStartPt;
   3.174  
   3.175        //fnPtr takes two params -- void *initData & void *animProcr
   3.176        //alloc stack locations, make stackPtr be the highest addr minus room
   3.177        // for 2 params + return addr.  Return addr (NULL) is in loc pointed to
   3.178        // by stackPtr, initData at stackPtr + 4 bytes, animatingPr just above
   3.179 -   stackLocs = malloc( VIRT_PROCR_STACK_SIZE );
   3.180 -   if(stackLocs == 0)
   3.181 -   {perror("malloc stack"); exit(1);}
   3.182 -   newPr->startOfStack = stackLocs;
   3.183     stackPtr = ( (char *)stackLocs + VIRT_PROCR_STACK_SIZE - 0x10 );
   3.184 +   
   3.185        //setup __cdecl on stack -- coreloop will switch to stackPtr before jmp
   3.186     *( (int *)stackPtr + 2 ) = (int) newPr; //rightmost param -- 32bit pointer
   3.187     *( (int *)stackPtr + 1 ) = (int) initialData;  //next  param to left
   3.188     newPr->stackPtr = stackPtr; //core loop will switch to this, then
   3.189     newPr->framePtr = stackPtr; //suspend loop will save new stack & frame ptr
   3.190  
   3.191 +   //============================= MEASUREMENT STUFF ========================
   3.192 +   #ifdef STATS__TURN_ON_PROBES
   3.193 +   struct timeval timeStamp;
   3.194 +   gettimeofday( &(timeStamp), NULL);
   3.195 +   newPr->createPtInSecs = timeStamp.tv_sec +(timeStamp.tv_usec/1000000.0);
   3.196 +   #endif
   3.197 +   //========================================================================
   3.198 +
   3.199     return newPr;
   3.200   }
   3.201  
   3.202 +inline VirtProcr *
   3.203 +VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   3.204 + { VirtProcr *newPr;
   3.205 +   char      *stackLocs;
   3.206 +
   3.207 +   newPr      = VMS__malloc( sizeof(VirtProcr) );
   3.208 +   stackLocs  = VMS__malloc( VIRT_PROCR_STACK_SIZE );
   3.209 +   if( stackLocs == 0 )
   3.210 +    { perror("VMS__malloc stack"); exit(1); }
   3.211 +   newPr->startOfStack = stackLocs;
   3.212 +
   3.213 +   return create_procr_helper( newPr, fnPtr, initialData, stackLocs );
   3.214 + }
   3.215 +
   3.216 +/* "ext" designates that it's for use outside the VMS system -- should only
   3.217 + * be called from main thread or other thread -- never from code animated by
   3.218 + * a VMS virtual processor.
   3.219 + */
   3.220 +inline VirtProcr *
   3.221 +VMS_ext__create_procr( VirtProcrFnPtr fnPtr, void *initialData )
   3.222 + { VirtProcr *newPr;
   3.223 +   char      *stackLocs;
   3.224 +
   3.225 +   newPr      = malloc( sizeof(VirtProcr) );
   3.226 +   stackLocs  = malloc( VIRT_PROCR_STACK_SIZE );
   3.227 +   if( stackLocs == 0 )
   3.228 +    { perror("malloc stack"); exit(1); }
   3.229 +   newPr->startOfStack = stackLocs;
   3.230 +
   3.231 +   return create_procr_helper( newPr, fnPtr, initialData, stackLocs );
   3.232 + }
   3.233 +
   3.234  
   3.235  /*there is a label inside this function -- save the addr of this label in
   3.236   * the callingPr struc, as the pick-up point from which to start the next
   3.237 @@ -339,7 +347,6 @@
   3.238  
   3.239        //return ownership of the virt procr and sched slot to Master virt pr
   3.240     animatingPr->schedSlot->workIsDone = TRUE;
   3.241 -//   coreIdx = callingPr->coreAnimatedBy;
   3.242  
   3.243     stackPtrAddr      = &(animatingPr->stackPtr);
   3.244     framePtrAddr      = &(animatingPr->framePtr);
   3.245 @@ -390,6 +397,31 @@
   3.246  
   3.247  
   3.248  
   3.249 +/*For this implementation of VMS, it may not make much sense to have the
   3.250 + * system of requests for creating a new processor done this way.. but over
   3.251 + * the scope of single-master, multi-master, mult-tasking, OS-implementing,
   3.252 + * distributed-memory, and so on, this gives VMS implementation a chance to
   3.253 + * do stuff before suspend, in the AppVP, and in the Master before the plugin
   3.254 + * is called, as well as in the lang-lib before this is called, and in the
   3.255 + * plugin.  So, this gives both VMS and language implementations a chance to
   3.256 + * intercept at various points and do order-dependent stuff.
   3.257 + *Having a standard VMSNewPrReqData struc allows the language to create and
   3.258 + * free the struc, while VMS knows how to get the newPr if it wants it, and
   3.259 + * it lets the lang have lang-specific data related to creation transported
   3.260 + * to the plugin.
   3.261 + */
   3.262 +void
   3.263 +VMS__send_create_procr_req( void *semReqData, VirtProcr *reqstingPr )
   3.264 + { VMSReqst req;
   3.265 +
   3.266 +   req.reqType          = createReq;
   3.267 +   req.semReqData       = semReqData;
   3.268 +   req.nextReqst        = reqstingPr->requests;
   3.269 +   reqstingPr->requests = &req;
   3.270 +
   3.271 +   VMS__suspend_procr( reqstingPr );
   3.272 + }
   3.273 +
   3.274  
   3.275  /*
   3.276   *This adds a request to dissipate, then suspends the processor so that the
   3.277 @@ -414,80 +446,93 @@
   3.278   */
   3.279  void
   3.280  VMS__dissipate_procr( VirtProcr *procrToDissipate )
   3.281 - { VMSReqst *req;
   3.282 + { VMSReqst req;
   3.283  
   3.284 -   req = malloc( sizeof(VMSReqst) );
   3.285 -//   req->virtProcrFrom      = callingPr;
   3.286 -   req->reqType               = dissipate;
   3.287 -   req->nextReqst             = procrToDissipate->requests;
   3.288 -   procrToDissipate->requests = req;
   3.289 -   
   3.290 +   req.reqType                = dissipate;
   3.291 +   req.nextReqst              = procrToDissipate->requests;
   3.292 +   procrToDissipate->requests = &req;
   3.293 +
   3.294     VMS__suspend_procr( procrToDissipate );
   3.295 -}
   3.296 + }
   3.297 +
   3.298 +
   3.299 +/* "ext" designates that it's for use outside the VMS system -- should only
   3.300 + * be called from main thread or other thread -- never from code animated by
   3.301 + * a VMS virtual processor.
   3.302 + *
   3.303 + *Use this version to dissipate VPs created outside the VMS system.
   3.304 + */
   3.305 +void
   3.306 +VMS_ext__dissipate_procr( VirtProcr *procrToDissipate )
   3.307 + {
   3.308 +      //NOTE: initialData was given to the processor, so should either have
   3.309 +      // been alloc'd with VMS__malloc, or freed by the level above animPr.
   3.310 +      //So, all that's left to free here is the stack and the VirtProcr struc
   3.311 +      // itself
   3.312 +      //Note, should not stack-allocate initial data -- no guarantee, in
   3.313 +      // general that creating processor will outlive ones it creates.
   3.314 +   free( procrToDissipate->startOfStack );
   3.315 +   free( procrToDissipate );
   3.316 + }
   3.317 +
   3.318  
   3.319  
   3.320  /*This inserts the semantic-layer's request data into standard VMS carrier
   3.321 + * request data-struct is allocated on stack of this call & ptr to it sent
   3.322 + * to plugin
   3.323   */
   3.324  inline void
   3.325  VMS__add_sem_request( void *semReqData, VirtProcr *callingPr )
   3.326 - { VMSReqst *req;
   3.327 + { VMSReqst req;
   3.328  
   3.329 -   req = malloc( sizeof(VMSReqst) );
   3.330 -//   req->virtProcrFrom      = callingPr;
   3.331 -   req->reqType        = semantic;
   3.332 -   req->semReqData     = semReqData;
   3.333 -   req->nextReqst      = callingPr->requests;
   3.334 -   callingPr->requests = req;
   3.335 +   req.reqType         = semantic;
   3.336 +   req.semReqData      = semReqData;
   3.337 +   req.nextReqst       = callingPr->requests;
   3.338 +   callingPr->requests = &req;
   3.339   }
   3.340  
   3.341 +/*This inserts the semantic-layer's request data into standard VMS carrier
   3.342 + * request data-struct is allocated on stack of this call & ptr to it sent
   3.343 + * to plugin
   3.344 + *Then it does suspend, to cause request to be sent.
   3.345 + */
   3.346 +inline void
   3.347 +VMS__send_sem_request( void *semReqData, VirtProcr *callingPr )
   3.348 + { VMSReqst req;
   3.349  
   3.350 -/*Use this to get first request before starting request handler's loop
   3.351 +   req.reqType         = semantic;
   3.352 +   req.semReqData      = semReqData;
   3.353 +   req.nextReqst       = callingPr->requests;
   3.354 +   callingPr->requests = &req;
   3.355 +   
   3.356 +   VMS__suspend_procr( callingPr );
   3.357 + }
   3.358 +
   3.359 +
   3.360 +inline void
   3.361 +VMS__send_VMSSem_request( void *semReqData, VirtProcr *callingPr )
   3.362 + { VMSReqst req;
   3.363 +
   3.364 +   req.reqType         = VMSSemantic;
   3.365 +   req.semReqData      = semReqData;
   3.366 +   req.nextReqst       = callingPr->requests; //gab any other preceeding 
   3.367 +   callingPr->requests = &req;
   3.368 +
   3.369 +   VMS__suspend_procr( callingPr );
   3.370 + }
   3.371 +
   3.372 +
   3.373 +/*
   3.374   */
   3.375  VMSReqst *
   3.376 -VMS__take_top_request_from( VirtProcr *procrWithReq )
   3.377 - { VMSReqst *req;
   3.378 -
   3.379 -   req = procrWithReq->requests;
   3.380 -   if( req == NULL ) return req;
   3.381 -
   3.382 -   procrWithReq->requests = procrWithReq->requests->nextReqst;
   3.383 -   return req;
   3.384 - }
   3.385 -
   3.386 -/*A subtle bug due to freeing then accessing "next" after freed caused this
   3.387 - * form of call to be put in -- so call this at end of request handler loop
   3.388 - * that iterates through the requests.
   3.389 - */
   3.390 -VMSReqst *
   3.391 -VMS__free_top_and_give_next_request_from( VirtProcr *procrWithReq )
   3.392 +VMS__take_next_request_out_of( VirtProcr *procrWithReq )
   3.393   { VMSReqst *req;
   3.394  
   3.395     req = procrWithReq->requests;
   3.396     if( req == NULL ) return NULL;
   3.397  
   3.398     procrWithReq->requests = procrWithReq->requests->nextReqst;
   3.399 -   VMS__free_request( req );
   3.400 -   return procrWithReq->requests;
   3.401 - }
   3.402 -
   3.403 -
   3.404 -//TODO: add a semantic-layer supplied "freer" for the semantic-data portion
   3.405 -// of a request -- IE call with both a virt procr and a fn-ptr to request
   3.406 -// freer (also maybe put sem request freer as a field in virt procr?)
   3.407 -//MeasVMS relies right now on this only freeing VMS layer of request -- the
   3.408 -// semantic portion of request is alloc'd and freed by request handler
   3.409 -void
   3.410 -VMS__free_request( VMSReqst *req )
   3.411 - {
   3.412 -   free( req );
   3.413 - }
   3.414 -
   3.415 -
   3.416 -
   3.417 -inline int
   3.418 -VMS__isSemanticReqst( VMSReqst *req )
   3.419 - {
   3.420 -   return ( req->reqType == semantic );
   3.421 +   return req;
   3.422   }
   3.423  
   3.424  
   3.425 @@ -497,36 +542,44 @@
   3.426     return req->semReqData;
   3.427   }
   3.428  
   3.429 -inline int
   3.430 -VMS__isDissipateReqst( VMSReqst *req )
   3.431 - {
   3.432 -   return ( req->reqType == dissipate );
   3.433 - }
   3.434  
   3.435 -inline int
   3.436 -VMS__isCreateReqst( VMSReqst *req )
   3.437 - {
   3.438 -   return ( req->reqType == regCreated );
   3.439 - }
   3.440  
   3.441 -void
   3.442 -VMS__send_req_to_register_new_procr(VirtProcr *newPr, VirtProcr *reqstingPr)
   3.443 - { VMSReqst *req;
   3.444 +/* This is for OS requests and VMS infrastructure requests, such as to create
   3.445 + *  a probe -- a probe is inside the heart of VMS-core, it's not part of any
   3.446 + *  language -- but it's also a semantic thing that's triggered from and used
   3.447 + *  in the application.. so it crosses abstractions..  so, need some special
   3.448 + *  pattern here for handling such requests.
   3.449 + * This is called from the language's request handler when it sees a request
   3.450 + *  of type VMSSemReq
   3.451 + */
   3.452 +void inline
   3.453 +VMS__handle_VMSSemReq( VMSReqst *req, VirtProcr *requestingPr, void *semEnv,
   3.454 +                       ResumePrFnPtr resumePrFnPtr )
   3.455 + { VMSSemReq     *semReq;
   3.456 +   IntervalProbe *newProbe;
   3.457 +   int32          nameLen;
   3.458  
   3.459 -   req                  = malloc( sizeof(VMSReqst) );
   3.460 -   req->reqType         = regCreated;
   3.461 -   req->semReqData      = newPr;
   3.462 -   req->nextReqst       = reqstingPr->requests;
   3.463 -   reqstingPr->requests = req;
   3.464 +   semReq = req->semReqData;
   3.465  
   3.466 -   VMS__suspend_procr( reqstingPr );
   3.467 +   newProbe          = VMS__malloc( sizeof(IntervalProbe) );
   3.468 +   nameLen = strlen( semReq->nameStr );
   3.469 +   newProbe->nameStr = VMS__malloc( nameLen );
   3.470 +   memcpy( newProbe->nameStr, semReq->nameStr, nameLen );
   3.471 +   newProbe->hist    = NULL;
   3.472 +   newProbe->schedChoiceWasRecorded = FALSE;
   3.473 +   newProbe->probeID =
   3.474 +             addToDynArray( newProbe, _VMSMasterEnv->dynIntervalProbesInfo );
   3.475 +
   3.476 +   requestingPr->dataReturnedFromReq = newProbe;
   3.477 +
   3.478 +   (*resumePrFnPtr)( requestingPr, semEnv );
   3.479   }
   3.480  
   3.481  
   3.482  
   3.483  /*This must be called by the request handler plugin -- it cannot be called
   3.484   * from the semantic library "dissipate processor" function -- instead, the
   3.485 - * semantic layer has to generate a request for the plug-in to call this
   3.486 + * semantic layer has to generate a request, and the plug-in calls this
   3.487   * function.
   3.488   *The reason is that this frees the virtual processor's stack -- which is
   3.489   * still in use inside semantic library calls!
   3.490 @@ -548,15 +601,15 @@
   3.491        // any locations that it is (was) sole owner of
   3.492  //TODO: implement VMS__malloc system, including "give up ownership"
   3.493  
   3.494 -      //The dissipate request might still be attached, so remove and free it
   3.495 -   VMS__free_top_and_give_next_request_from( animatingPr );
   3.496  
   3.497        //NOTE: initialData was given to the processor, so should either have
   3.498        // been alloc'd with VMS__malloc, or freed by the level above animPr.
   3.499        //So, all that's left to free here is the stack and the VirtProcr struc
   3.500        // itself
   3.501 -   free( animatingPr->startOfStack );
   3.502 -   free( animatingPr );
   3.503 +      //Note, should not stack-allocate initial data -- no guarantee, in
   3.504 +      // general that creating processor will outlive ones it creates.
   3.505 +   VMS__free( animatingPr->startOfStack );
   3.506 +   VMS__free( animatingPr );
   3.507   }
   3.508  
   3.509  
   3.510 @@ -603,7 +656,7 @@
   3.511        //create the shutdown processors, one for each core loop -- put them
   3.512        // directly into the Q -- each core will die when gets one
   3.513     for( coreIdx=0; coreIdx < NUM_CORES; coreIdx++ )
   3.514 -    {
   3.515 +    {    //Note, this is running in the master
   3.516        shutDownPr = VMS__create_procr( &endOSThreadFn, NULL );
   3.517        writeSRSWQ( shutDownPr, _VMSMasterEnv->readyToAnimateQs[coreIdx] );
   3.518      }
   3.519 @@ -664,8 +717,8 @@
   3.520     for( coreIdx = 0; coreIdx < NUM_CORES; coreIdx++ )
   3.521      {
   3.522        freeSRSWQ( readyToAnimateQs[ coreIdx ] );
   3.523 -
   3.524 -      VMS__handle_dissipate_reqst( masterVPs[ coreIdx ] );
   3.525 +         //master VPs were created external to VMS, so use external free
   3.526 +      VMS_ext__dissipate_procr( masterVPs[ coreIdx ] );
   3.527        
   3.528        freeSchedSlots( allSchedSlots[ coreIdx ] );
   3.529      }
   3.530 @@ -673,20 +726,15 @@
   3.531     free( _VMSMasterEnv->readyToAnimateQs );
   3.532     free( _VMSMasterEnv->masterVPs );
   3.533     free( _VMSMasterEnv->allSchedSlots );
   3.534 +   
   3.535 +   VMS_ext__free_free_list( _VMSMasterEnv->freeListHead );
   3.536 +
   3.537 +   //============================= MEASUREMENT STUFF ========================
   3.538 +   #ifdef STATS__TURN_ON_PROBES
   3.539 +   freeDynArrayDeep( _VMSMasterEnv->dynIntervalProbesInfo, &free );
   3.540 +   #endif
   3.541 +   //========================================================================
   3.542  
   3.543     free( _VMSMasterEnv );
   3.544   }
   3.545  
   3.546 -
   3.547 -//===========================================================================
   3.548 -
   3.549 -inline TSCount getTSCount()
   3.550 - { unsigned int low, high;
   3.551 -   TSCount  out;
   3.552 -
   3.553 -   saveTimeStampCountInto( low, high );
   3.554 -   out = high;
   3.555 -   out = (out << 32) + low;
   3.556 -   return out;
   3.557 - }
   3.558 -
     4.1 --- a/VMS.h	Thu Oct 14 17:07:23 2010 -0700
     4.2 +++ b/VMS.h	Sat Oct 30 20:54:36 2010 -0700
     4.3 @@ -13,17 +13,31 @@
     4.4  #include "VMS_primitive_data_types.h"
     4.5  #include "Queue_impl/BlockingQueue.h"
     4.6  #include "Histogram/Histogram.h"
     4.7 +#include "DynArray/DynArray.h"
     4.8 +#include "Hash_impl/PrivateHash.h"
     4.9 +#include "vmalloc.h"
    4.10 +
    4.11  #include <pthread.h>
    4.12 +#include <sys/time.h>
    4.13  
    4.14 +
    4.15 +//===============================  Debug  ===================================
    4.16     //When SEQUENTIAL is defined, VMS does sequential exe in the main thread
    4.17     // It still does co-routines and all the mechanisms are the same, it just
    4.18     // has only a single thread and animates VPs one at a time
    4.19  //#define SEQUENTIAL
    4.20  
    4.21 -#define PRINT_DEBUG(msg) //printf(msg); fflush(stdin);
    4.22 +#define PRINT_DEBUG(msg)// printf(msg); fflush(stdin);
    4.23  #define PRINT1_DEBUG(msg, param) //printf(msg, param); fflush(stdin);
    4.24  #define PRINT2_DEBUG(msg, p1, p2) //printf(msg, p1, p2); fflush(stdin);
    4.25  
    4.26 +#define PRINT_ERROR(msg) printf(msg); fflush(stdin);
    4.27 +#define PRINT1_ERROR(msg, param) printf(msg, param); fflush(stdin);
    4.28 +#define PRINT2_ERROR(msg, p1, p2) printf(msg, p1, p2); fflush(stdin);
    4.29 +
    4.30 +
    4.31 +//===========================  STATS =======================
    4.32 +
    4.33     //when MEAS__TIME_STAMP_SUSP is defined, causes code to be inserted and
    4.34     // compiled-in that saves the low part of the time stamp count just before
    4.35     // suspending a processor and just after resuming that processor.  It is
    4.36 @@ -35,6 +49,8 @@
    4.37  
    4.38  #define NUM_TSC_ROUND_TRIPS 10
    4.39  
    4.40 +
    4.41 +//=========================  Hardware related Constants =====================
    4.42     //This value is the number of hardware threads in the shared memory
    4.43     // machine
    4.44  #define NUM_CORES        4
    4.45 @@ -47,39 +63,75 @@
    4.46  #define READYTOANIMATE_RETRIES 10000
    4.47  
    4.48     // stack
    4.49 -#define VIRT_PROCR_STACK_SIZE 0x10000
    4.50 +#define VIRT_PROCR_STACK_SIZE 0x4000
    4.51  
    4.52 -   //256M of total memory for VMS__malloc
    4.53 -#define MASSIVE_MALLOC_SIZE 0x10000000
    4.54 +   // memory for VMS__malloc -- 256M
    4.55 +#define MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE 0x10000000
    4.56  
    4.57 -#define NUM_PREPEND_BYTES sizeof(FreeListElem) + sizeof(ownerElem);
    4.58 +
    4.59 +//==============================
    4.60  
    4.61  #define SUCCESS 0
    4.62  
    4.63 -#define writeVMSQ     writeCASQ
    4.64 -#define readVMSQ      readCASQ
    4.65 -#define makeVMSQ      makeCASQ
    4.66 -#define VMSQueueStruc CASQueueStruc
    4.67 +#define writeVMSQ     writeSRSWQ
    4.68 +#define readVMSQ      readSRSWQ
    4.69 +#define makeVMSQ      makeSRSWQ
    4.70 +#define VMSQueueStruc SRSWQueueStruc
    4.71  
    4.72 -//#define thdAttrs NULL  //For PThreads
    4.73  
    4.74 -typedef struct _SchedSlot  SchedSlot;
    4.75 -typedef struct _VMSReqst   VMSReqst;
    4.76 -typedef struct _VirtProcr  VirtProcr;
    4.77 +
    4.78 +//===========================================================================
    4.79 +typedef unsigned long long TSCount;
    4.80 +
    4.81 +typedef struct _SchedSlot     SchedSlot;
    4.82 +typedef struct _VMSReqst      VMSReqst;
    4.83 +typedef struct _VirtProcr     VirtProcr;
    4.84 +typedef struct _IntervalProbe IntervalProbe;
    4.85  
    4.86  typedef VirtProcr * (*SlaveScheduler)  ( void *, int );   //semEnv, coreIdx
    4.87  typedef void  (*RequestHandler)  ( VirtProcr *, void * ); //prWReqst, semEnv
    4.88  typedef void  (*VirtProcrFnPtr)  ( void *, VirtProcr * ); //initData, animPr
    4.89  typedef void    VirtProcrFn      ( void *, VirtProcr * ); //initData, animPr
    4.90 +typedef void  (*ResumePrFnPtr)   ( VirtProcr *, void * );
    4.91 +
    4.92 +
    4.93 +//============= Requests ===========
    4.94 +//
    4.95 +
    4.96 +enum VMSReqstType   //avoid starting enums at 0, for debug reasons
    4.97 + {
    4.98 +   semantic = 1,
    4.99 +   createReq,
   4.100 +   dissipate,
   4.101 +   VMSSemantic      //goes with VMSSemReqst below
   4.102 + };
   4.103 +
   4.104 +struct _VMSReqst
   4.105 + {
   4.106 +   enum VMSReqstType  reqType;//used for dissipate and in future for IO requests
   4.107 +   void              *semReqData;
   4.108 +
   4.109 +   VMSReqst *nextReqst;
   4.110 + };
   4.111 +//VMSReqst
   4.112 +
   4.113 +enum VMSSemReqstType   //These are equivalent to semantic requests, but for
   4.114 + {                     // VMS's services available directly to app, like OS
   4.115 +   createProbe = 1,    // and probe services -- like a VMS-wide built-in lang
   4.116 +   openFile,
   4.117 +   otherIO
   4.118 + };
   4.119  
   4.120  typedef struct
   4.121 - {
   4.122 -   void           *endThdPt;
   4.123 -   unsigned int    coreNum;
   4.124 + { enum VMSSemReqstType reqType;
   4.125 +   VirtProcr           *requestingPr;
   4.126 +   char                *nameStr;  //for create probe
   4.127   }
   4.128 -ThdParams;
   4.129 + VMSSemReq;
   4.130  
   4.131  
   4.132 +//====================  Core data structures  ===================
   4.133 +
   4.134  struct _SchedSlot
   4.135   {
   4.136     int         workIsDone;
   4.137 @@ -87,24 +139,6 @@
   4.138     VirtProcr  *procrAssignedToSlot;
   4.139   };
   4.140  //SchedSlot
   4.141 - 
   4.142 -enum ReqstType
   4.143 - {
   4.144 -   semantic = 1,
   4.145 -   dissipate,
   4.146 -   regCreated,
   4.147 -   IO
   4.148 - };
   4.149 -
   4.150 -struct _VMSReqst
   4.151 - {
   4.152 -//   VirtProcr   *virtProcrFrom;
   4.153 -   enum ReqstType  reqType;//used for dissipate and in future for IO requests
   4.154 -   void           *semReqData;
   4.155 -
   4.156 -   VMSReqst *nextReqst;
   4.157 - };
   4.158 -//VMSReqst
   4.159  
   4.160  struct _VirtProcr
   4.161   { int         procrID;  //for debugging -- count up each time create
   4.162 @@ -123,9 +157,10 @@
   4.163     SchedSlot  *schedSlot;
   4.164     VMSReqst   *requests;
   4.165  
   4.166 -   void       *semanticData;
   4.167 +   void       *semanticData; //this lives here for the life of VP
   4.168 +   void       *dataReturnedFromReq;//values returned from plugin to VP go here
   4.169  
   4.170 -   //============================= MEASUREMENT STUFF ========================
   4.171 +      //=========== MEASUREMENT STUFF ==========
   4.172     #ifdef MEAS__TIME_STAMP_SUSP
   4.173     unsigned int preSuspTSCLow;
   4.174     unsigned int postSuspTSCLow;
   4.175 @@ -134,12 +169,12 @@
   4.176     unsigned int startMasterTSCLow;
   4.177     unsigned int endMasterTSCLow;
   4.178     #endif
   4.179 -   //========================================================================
   4.180 +   
   4.181 +   float64      createPtInSecs;  //have space but don't use on some configs
   4.182   };
   4.183  //VirtProcr
   4.184  
   4.185  
   4.186 -
   4.187  typedef struct
   4.188   {
   4.189     SlaveScheduler   slaveScheduler;
   4.190 @@ -151,35 +186,61 @@
   4.191  
   4.192     void            *semanticEnv;
   4.193     void            *OSEventStruc;   //for future, when add I/O to BLIS
   4.194 +   MallocProlog    *freeListHead;
   4.195 +   int32            amtOfOutstandingMem; //total currently allocated
   4.196  
   4.197     void            *coreLoopStartPt;//addr to jump to to re-enter coreLoop
   4.198     void            *coreLoopEndPt;  //addr to jump to to shut down a coreLoop
   4.199  
   4.200 -   int              setupComplete;
   4.201 -   int              masterLock;
   4.202 +   int32            setupComplete;
   4.203 +   int32            masterLock;
   4.204  
   4.205 +   int32            numMasterInARow[NUM_CORES];//detect back-to-back masterVP
   4.206 +   int32            numProcrsCreated; //gives ordering to processor creation
   4.207 +
   4.208 +      //=========== MEASUREMENT STUFF =============
   4.209 +   IntervalProbe  **intervalProbes;
   4.210 +   DynArrayInfo    *dynIntervalProbesInfo;
   4.211 +   HashTable       *probeNameHashTbl;
   4.212 +   int32            masterCreateProbeID;
   4.213 +   float64          createPtInSecs;
   4.214   }
   4.215  MasterEnv;
   4.216  
   4.217  
   4.218 -//==========================================================
   4.219 +
   4.220 +
   4.221 +//=======================  OS Thread related  ===============================
   4.222  
   4.223  void * coreLoop( void *paramsIn );  //standard PThreads fn prototype
   4.224  void * coreLoop_Seq( void *paramsIn );  //standard PThreads fn prototype
   4.225  void masterLoop( void *initData, VirtProcr *masterPr );
   4.226  
   4.227  
   4.228 -//=====================  Global Vars ===================
   4.229 -
   4.230 +typedef struct
   4.231 + {
   4.232 +   void           *endThdPt;
   4.233 +   unsigned int    coreNum;
   4.234 + }
   4.235 +ThdParams;
   4.236  
   4.237  pthread_t       coreLoopThdHandles[ NUM_CORES ];  //pthread's virt-procr state
   4.238  ThdParams      *coreLoopThdParams [ NUM_CORES ];
   4.239  pthread_mutex_t suspendLock;
   4.240  pthread_cond_t  suspend_cond;
   4.241  
   4.242 +
   4.243 +
   4.244 +//=====================  Global Vars ===================
   4.245 +
   4.246  volatile MasterEnv      *_VMSMasterEnv;
   4.247  
   4.248 -//==========================
   4.249 +
   4.250 +
   4.251 +
   4.252 +//===========================  Function Prototypes  =========================
   4.253 +
   4.254 +//============== Setup and shutdown =============
   4.255  void
   4.256  VMS__init();
   4.257  
   4.258 @@ -195,16 +256,28 @@
   4.259  VirtProcr *
   4.260  VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData );
   4.261  
   4.262 +   //Use this to create processor inside entry point & other places outside
   4.263 +   // the VMS system boundary (IE, not run in slave nor Master)
   4.264 +VirtProcr *
   4.265 +VMS_ext__create_procr( VirtProcrFnPtr fnPtr, void *initialData );
   4.266 +
   4.267  VirtProcr *
   4.268  VMS__create_the_shutdown_procr();
   4.269  
   4.270 -//==========================
   4.271 +void
   4.272 +VMS__cleanup_after_shutdown();
   4.273 +
   4.274 +
   4.275 +//==============  Request Related  ===============
   4.276 +
   4.277 +void
   4.278 +VMS__suspend_procr( VirtProcr *callingPr );
   4.279 +
   4.280  inline void
   4.281  VMS__add_sem_request( void *semReqData, VirtProcr *callingPr );
   4.282  
   4.283  void
   4.284 -VMS__send_req_to_register_new_procr( VirtProcr *newPrToRegister,
   4.285 -                                      VirtProcr *reqstingPr );
   4.286 +VMS__send_create_procr_req( void *semReqData, VirtProcr *reqstingPr );
   4.287  
   4.288  void
   4.289  VMS__free_request( VMSReqst *req );
   4.290 @@ -216,7 +289,7 @@
   4.291  VMS__take_top_request_from( VirtProcr *reqstingPr );
   4.292  
   4.293  VMSReqst *
   4.294 -VMS__free_top_and_give_next_request_from( VirtProcr *procrWithReq );
   4.295 +VMS__take_next_request_out_of( VirtProcr *procrWithReq );
   4.296  
   4.297  inline void *
   4.298  VMS__take_sem_reqst_from( VMSReqst *req );
   4.299 @@ -232,25 +305,15 @@
   4.300  
   4.301  //==========================
   4.302  
   4.303 -void
   4.304 -VMS__suspend_procr( VirtProcr *callingPr );
   4.305 -
   4.306 -void
   4.307 +void inline
   4.308  VMS__dissipate_procr( VirtProcr *prToDissipate );
   4.309  
   4.310  void
   4.311  VMS__handle_dissipate_reqst( VirtProcr *procrToDissipate );
   4.312  
   4.313 -void
   4.314 -VMS__cleanup_after_shutdown();
   4.315  
   4.316 -//============================= Statistics ==================================
   4.317  
   4.318 -typedef unsigned long long TSCount;
   4.319 -
   4.320 -   //Frequency of TS counts
   4.321 -   //TODO: change freq for each machine
   4.322 -#define TSCOUNT_FREQ 3180000000
   4.323 +//===================== RDTSC wrapper ==================
   4.324  
   4.325  #define saveTimeStampCountInto(low, high) \
   4.326     asm volatile("RDTSC;                   \
   4.327 @@ -269,11 +332,9 @@
   4.328     /* clobber */ : "%eax", "%edx"         \
   4.329                  );
   4.330  
   4.331 -inline TSCount getTSCount();
   4.332 +//======================== STATS ======================
   4.333  
   4.334 -//===================== Debug ==========================
   4.335 -int numProcrsCreated;
   4.336 -
   4.337 +#include "probes.h"
   4.338  
   4.339  #endif	/* _VMS_H */
   4.340  
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/probes.c	Sat Oct 30 20:54:36 2010 -0700
     5.3 @@ -0,0 +1,342 @@
     5.4 +/*
     5.5 + * Copyright 2010  OpenSourceStewardshipFoundation
     5.6 + *
     5.7 + * Licensed under BSD
     5.8 + */
     5.9 +
    5.10 +#include <stdio.h>
    5.11 +#include <stdlib.h>
    5.12 +#include <malloc.h>
    5.13 +#include <sys/time.h>
    5.14 +
    5.15 +#include "VMS.h"
    5.16 +#include "Queue_impl/BlockingQueue.h"
    5.17 +#include "Histogram/Histogram.h"
    5.18 +
    5.19 +
    5.20 +//================================ STATS ====================================
    5.21 +
    5.22 +inline TSCount getTSCount()
    5.23 + { unsigned int low, high;
    5.24 +   TSCount  out;
    5.25 +
    5.26 +   saveTimeStampCountInto( low, high );
    5.27 +   out = high;
    5.28 +   out = (out << 32) + low;
    5.29 +   return out;
    5.30 + }
    5.31 +
    5.32 +
    5.33 +
    5.34 +//====================  Probes =================
    5.35 +#ifdef STATS__USE_TSC_PROBES
    5.36 +int32
    5.37 +VMS__create_single_interval_probe( char *nameStr )
    5.38 + { IntervalProbe *newProbe;
    5.39 +   int32 idx;
    5.40 +
    5.41 +   newProbe = malloc( sizeof(IntervalProbe) );
    5.42 +   newProbe->nameStr = nameStr;  //caller frees if not constant on stack
    5.43 +   newProbe->hist = NULL;
    5.44 +   idx = addToDynArray( newProbe, _VMSMasterEnv->dynIntervalProbesInfo );
    5.45 +   return idx;
    5.46 + }
    5.47 +
    5.48 +int32
    5.49 +VMS__create_histogram_probe( int32 numBins, float32 startValue,
    5.50 +                             float32 binWidth, char *nameStr )
    5.51 + { IntervalProbe *newProbe;
    5.52 +   int32 idx;
    5.53 +   FloatHist *hist;
    5.54 +
    5.55 +   idx = VMS__create_single_interval_probe( nameStr );
    5.56 +   newProbe =  _VMSMasterEnv->intervalProbes[ idx ];
    5.57 +
    5.58 +   hist =  makeFloatHistogram( numBins, startValue, binWidth );
    5.59 +   newProbe->hist = hist;
    5.60 +   return idx;
    5.61 + }
    5.62 +
    5.63 +void
    5.64 +VMS_impl__record_interval_start_in_probe( int32 probeID )
    5.65 + { IntervalProbe *probe;
    5.66 +
    5.67 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
    5.68 +   probe->startStamp = getTSCount();
    5.69 + }
    5.70 +
    5.71 +void
    5.72 +VMS_impl__record_interval_end_in_probe( int32 probeID )
    5.73 + { IntervalProbe *probe;
    5.74 +   TSCount endStamp;
    5.75 +
    5.76 +   endStamp = getTSCount();
    5.77 +
    5.78 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
    5.79 +   probe->endStamp = endStamp;
    5.80 +
    5.81 +   if( probe->hist != NULL )
    5.82 +    { TSCount interval = probe->endStamp - probe->startStamp;
    5.83 +         //if the interval is sane, then add to histogram
    5.84 +      if( interval < probe->hist->endOfRange * 10 )
    5.85 +         addToFloatHist( interval, probe->hist );
    5.86 +    }
    5.87 + }
    5.88 +
    5.89 +void
    5.90 +VMS_impl__print_stats_of_probe( int32 probeID )
    5.91 + { IntervalProbe *probe;
    5.92 +
    5.93 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
    5.94 +
    5.95 +   if( probe->hist == NULL )
    5.96 +    {
    5.97 +      printf("probe: %s, interval: %.6lf\n", probe->nameStr,probe->interval);
    5.98 +    }
    5.99 +
   5.100 +   else
   5.101 +    {
   5.102 +      printf( "probe: %s\n", probe->nameStr );
   5.103 +      printFloatHist( probe->hist );
   5.104 +    }
   5.105 + }
   5.106 +#else
   5.107 +#ifdef STATS__USE_DBL_PROBES
   5.108 +
   5.109 +/*
   5.110 + * In practice, probe operations are called from the app, from inside slaves
   5.111 + *  -- so have to be sure each probe is single-VP owned, and be sure that
   5.112 + *  any place common structures are modified it's done inside the master.
   5.113 + * So -- the only place common structures are modified is during creation.
   5.114 + *  after that, all mods are to individual instances.
   5.115 + *
   5.116 + * Thniking perhaps should change the semantics to be that probes are
   5.117 + *  attached to the virtual processor -- and then everything is guaranteed
   5.118 + *  to be isolated -- except then can't take any intervals that span VPs,
   5.119 + *  and would have to transfer the probes to Master env when VP dissipates..
   5.120 + *  gets messy..
   5.121 + *
   5.122 + * For now, just making so that probe creation causes a suspend, so that
   5.123 + *  the dynamic array in the master env is only modified from the master
   5.124 + * 
   5.125 + */
   5.126 +IntervalProbe *
   5.127 +create_generic_probe( char *nameStr, VirtProcr *animPr )
   5.128 + { IntervalProbe *newProbe;
   5.129 +   int32 idx;
   5.130 +   VMSSemReq reqData;
   5.131 +
   5.132 +   reqData.reqType  = createProbe;
   5.133 +   reqData.nameStr  = nameStr;
   5.134 +
   5.135 +   VMS__send_VMSSem_request( reqData, animPr );
   5.136 +
   5.137 +   return animPr->dataReturnedFromReq;
   5.138 + }
   5.139 +
   5.140 +int32
   5.141 +VMS_impl__record_time_point_into_new_probe( char *nameStr, VirtProcr *animPr )
   5.142 + { IntervalProbe *newProbe;
   5.143 +   struct timeval *startStamp;
   5.144 +   float64 startSecs;
   5.145 +
   5.146 +   newProbe           = create_generic_probe( nameStr, animPr );
   5.147 +   newProbe->endSecs  = 0;
   5.148 +
   5.149 +   gettimeofday( &(newProbe->startStamp), NULL);
   5.150 +
   5.151 +      //turn into a double
   5.152 +   startStamp = &(newProbe->startStamp);
   5.153 +   startSecs = startStamp->tv_sec + ( startStamp->tv_usec / 1000000.0 );
   5.154 +   newProbe->startSecs = startSecs;
   5.155 +
   5.156 +   return newProbe->probeID;
   5.157 + }
   5.158 +
   5.159 +int32
   5.160 +VMS_impl__create_single_interval_probe( char *nameStr, VirtProcr *animPr )
   5.161 + { IntervalProbe *newProbe;
   5.162 +
   5.163 +   newProbe = create_generic_probe( nameStr, animPr );
   5.164 +   
   5.165 +   return newProbe->probeID;
   5.166 + }
   5.167 +
   5.168 +int32
   5.169 +VMS_impl__create_histogram_probe( int32   numBins, float64    startValue,
   5.170 +               float64 binWidth, char   *nameStr, VirtProcr *animPr )
   5.171 + { IntervalProbe *newProbe;
   5.172 +   DblHist *hist;
   5.173 +
   5.174 +   newProbe = create_generic_probe( nameStr, animPr );
   5.175 +   
   5.176 +   hist =  makeDblHistogram( numBins, startValue, binWidth );
   5.177 +   newProbe->hist = hist;
   5.178 +   return newProbe->probeID;
   5.179 + }
   5.180 +
   5.181 +void
   5.182 +VMS_impl__index_probe_by_its_name( int32 probeID, VirtProcr *animPr )
   5.183 + { IntervalProbe *probe;
   5.184 +
   5.185 +   //TODO: fix this To be in Master -- race condition
   5.186 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
   5.187 +
   5.188 +   addValueIntoTable(probe->nameStr, probe, _VMSMasterEnv->probeNameHashTbl);
   5.189 + }
   5.190 +
   5.191 +IntervalProbe *
   5.192 +VMS_impl__get_probe_by_name( char *probeName, VirtProcr *animPr )
   5.193 + {
   5.194 +   //TODO: fix this To be in Master -- race condition
   5.195 +   return getValueFromTable( probeName, _VMSMasterEnv->probeNameHashTbl );
   5.196 + }
   5.197 +
   5.198 +
   5.199 +/*Everything is local to the animating procr, so no need for request, do
   5.200 + * work locally, in the anim Pr
   5.201 + */
   5.202 +void
   5.203 +VMS_impl__record_sched_choice_into_probe( int32 probeID, VirtProcr *animatingPr )
   5.204 + { IntervalProbe *probe;
   5.205 + 
   5.206 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
   5.207 +   probe->schedChoiceWasRecorded = TRUE;
   5.208 +   probe->coreNum = animatingPr->coreAnimatedBy;
   5.209 +   probe->procrID = animatingPr->procrID;
   5.210 +   probe->procrCreateSecs = 0;
   5.211 + }
   5.212 +
   5.213 +/*Everything is local to the animating procr, so no need for request, do
   5.214 + * work locally, in the anim Pr
   5.215 + */
   5.216 +void
   5.217 +VMS_impl__record_interval_start_in_probe( int32 probeID )
   5.218 + { IntervalProbe *probe;
   5.219 +
   5.220 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
   5.221 +   gettimeofday( &(probe->startStamp), NULL );
   5.222 + }
   5.223 +
   5.224 +
   5.225 +/*Everything is local to the animating procr, so no need for request, do
   5.226 + * work locally, in the anim Pr
   5.227 + */
   5.228 +void
   5.229 +VMS_impl__record_interval_end_in_probe( int32 probeID )
   5.230 + { IntervalProbe *probe;
   5.231 +   struct timeval *endStamp, *startStamp;
   5.232 +   double startSecs, endSecs;
   5.233 +
   5.234 +      //possible seg-fault if array resized by diff core right after this
   5.235 +      // one gets probe..?  Something like that?  Might be safe.. don't care
   5.236 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
   5.237 +   gettimeofday( &(probe->endStamp), NULL);
   5.238 +
   5.239 +      //now turn into an interval held in a double
   5.240 +   startStamp = &(probe->startStamp);
   5.241 +   endStamp   = &(probe->endStamp);
   5.242 +
   5.243 +   startSecs = startStamp->tv_sec + ( startStamp->tv_usec / 1000000.0 );
   5.244 +   endSecs   = endStamp->tv_sec   + ( endStamp->tv_usec / 1000000.0 );
   5.245 +
   5.246 +   probe->interval  = endSecs - startSecs;
   5.247 +   probe->startSecs = startSecs;
   5.248 +   probe->endSecs   = endSecs;
   5.249 +
   5.250 +   if( probe->hist != NULL )
   5.251 +    {
   5.252 +         //if the interval is sane, then add to histogram
   5.253 +      if( probe->interval < probe->hist->endOfRange * 10 )
   5.254 +         addToDblHist( probe->interval, probe->hist );
   5.255 +    }
   5.256 + }
   5.257 +
   5.258 +void
   5.259 +print_probe_helper( IntervalProbe *probe )
   5.260 + {
   5.261 +   printf( "\nprobe: %s, ",  probe->nameStr );
   5.262 +   
   5.263 +   if( probe->schedChoiceWasRecorded )
   5.264 +    { printf( "coreNum: %d, procrID: %d, procrCreated: %.6lf | ",
   5.265 +              probe->coreNum, probe->procrID, probe->procrCreateSecs );
   5.266 +    }
   5.267 +
   5.268 +   if( probe->endSecs == 0 ) //just a single point in time
   5.269 +    {
   5.270 +      printf( " time point: %.6lf\n",
   5.271 +              probe->startSecs - _VMSMasterEnv->createPtInSecs );
   5.272 +    }
   5.273 +   else if( probe->hist == NULL ) //just an interval
   5.274 +    {
   5.275 +      printf( " startSecs: %.6lf, interval: %.6lf\n", 
   5.276 +         probe->startSecs - _VMSMasterEnv->createPtInSecs, probe->interval);
   5.277 +    }
   5.278 +   else  //a full histogram of intervals
   5.279 +    {
   5.280 +      printDblHist( probe->hist );
   5.281 +    }
   5.282 + }
   5.283 +
   5.284 +//TODO: change so pass around pointer to probe instead of its array-index..
   5.285 +// will eliminate chance for timing of resize to cause problems with the
   5.286 +// lookup -- even though don't think it actually can cause problems..
   5.287 +// there's no need to pass index around -- have hash table for names, and
   5.288 +// only need it once, then have ptr to probe..  the thing about enum the
   5.289 +// index and use that as name is clunky in practice -- just hash.
   5.290 +void
   5.291 +VMS_impl__print_stats_of_probe( int32 probeID )
   5.292 + { IntervalProbe *probe;
   5.293 +
   5.294 +   probe = _VMSMasterEnv->intervalProbes[ probeID ];
   5.295 +
   5.296 +   print_probe_helper( probe );
   5.297 + }
   5.298 +
   5.299 +
   5.300 +
   5.301 +void
   5.302 +generic_print_probe( void *_probe )
   5.303 + { IntervalProbe *probe;
   5.304 +
   5.305 +   probe = (IntervalProbe *)_probe;
   5.306 +   print_probe_helper( probe );
   5.307 + }
   5.308 +
   5.309 +void
   5.310 +VMS_impl__print_stats_of_all_probes()
   5.311 + { IntervalProbe *probe;
   5.312 +
   5.313 +   forAllInDynArrayDo( _VMSMasterEnv->dynIntervalProbesInfo,
   5.314 +                       &generic_print_probe );
   5.315 +   fflush( stdout );
   5.316 + }
   5.317 +#endif
   5.318 +#endif
   5.319 +
   5.320 +/* Junk left over from when trying the different ways to get time stamps..
   5.321 +         struct timeval tim;
   5.322 +         gettimeofday(&tim, NULL);
   5.323 +         double t1=tim.tv_sec+(tim.tv_usec/1000000.0);
   5.324 +
   5.325 +         clock_t startClockStamp = clock();
   5.326 +
   5.327 +         TSCount startMultStamp = getTSCount();
   5.328 +*/
   5.329 +
   5.330 +/*
   5.331 +         TSCount endMultStamp = getTSCount();
   5.332 +
   5.333 +         dividerParams->numTSCsToExe = endMultStamp - startMultStamp;
   5.334 +         printf("\ntime to execute: %d\n", endMultStamp - startMultStamp);
   5.335 +
   5.336 +         //==================================================================
   5.337 +         clock_t endClockStamp = clock();
   5.338 +         printf("%.4lf seconds of processing\n",
   5.339 +                (endClockStamp - startClockStamp)/(double)CLOCKS_PER_SEC);
   5.340 +
   5.341 +         //==================================================================
   5.342 +         gettimeofday(&tim, NULL);
   5.343 +         double t2=tim.tv_sec+(tim.tv_usec/1000000.0);
   5.344 +         printf("%.6lf seconds elapsed\n", t2-t1);
   5.345 +*/
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/probes.h	Sat Oct 30 20:54:36 2010 -0700
     6.3 @@ -0,0 +1,193 @@
     6.4 +/*
     6.5 + *  Copyright 2009 OpenSourceStewardshipFoundation.org
     6.6 + *  Licensed under GNU General Public License version 2
     6.7 + *
     6.8 + * Author: seanhalle@yahoo.com
     6.9 + * 
    6.10 + */
    6.11 +
    6.12 +#ifndef _PROBES_H
    6.13 +#define	_PROBES_H
    6.14 +#define __USE_GNU
    6.15 +
    6.16 +#include "VMS_primitive_data_types.h"
    6.17 +
    6.18 +#include <sys/time.h>
    6.19 +
    6.20 +   //turns on the probe-instrumentation in the application -- when not
    6.21 +   // defined, the calls to the probe functions turn into comments
    6.22 +//#define STATS__ENABLE_PROBES
    6.23 +
    6.24 +   //when STATS__TURN_ON_PROBES is defined allows using probes to measure
    6.25 +   // time intervals.  The probes are macros that only compile to something
    6.26 +   // when STATS__TURN_ON_PROBES is defined.  The probes are saved in the
    6.27 +   // master env -- but only when this is defined.
    6.28 +   //The TSC probes use RDTSC instr, can be unreliable, Dbl uses gettimeofday
    6.29 +#define STATS__TURN_ON_PROBES
    6.30 +//#define STATS__USE_TSC_PROBES
    6.31 +#define STATS__USE_DBL_PROBES
    6.32 +
    6.33 +//typedef struct _IntervalProbe IntervalProbe; //in VMS.h
    6.34 +
    6.35 +struct _IntervalProbe
    6.36 + {
    6.37 +   char           *nameStr;
    6.38 +   int32           probeID;
    6.39 +
    6.40 +   int32           schedChoiceWasRecorded;
    6.41 +   int32           coreNum;
    6.42 +   int32           procrID;
    6.43 +   float64         procrCreateSecs;
    6.44 +
    6.45 +   #ifdef STATS__USE_TSC_PROBES
    6.46 +   TSCount    startStamp;
    6.47 +   TSCount    endStamp;
    6.48 +   #else
    6.49 +   struct timeval  startStamp;
    6.50 +   struct timeval  endStamp;
    6.51 +   #endif
    6.52 +   float64         startSecs;
    6.53 +   float64         endSecs;
    6.54 +   float64         interval;
    6.55 +   DblHist        *hist;//if NULL, then is single interval probe
    6.56 + };
    6.57 +
    6.58 +
    6.59 +//============================= Statistics ==================================
    6.60 +
    6.61 +   //Frequency of TS counts
    6.62 +   //TODO: change freq for each machine
    6.63 +#define TSCOUNT_FREQ 3180000000
    6.64 +
    6.65 +inline TSCount getTSCount();
    6.66 +
    6.67 +
    6.68 +//======================== Probes =============================
    6.69 +//
    6.70 +// Use macros to allow turning probes off with a #define switch
    6.71 +#ifdef STATS__ENABLE_PROBES
    6.72 +int32
    6.73 +VMS_impl__record_time_point_into_new_probe( char *nameStr,VirtProcr *animPr);
    6.74 +#define VMS__record_time_point_into_new_probe( nameStr, animPr ) \
    6.75 +        VMS_impl__record_time_point_in_new_probe( nameStr, animPr )
    6.76 +
    6.77 +int32
    6.78 +VMS_ext_impl__record_time_point_into_new_probe( char *nameStr, VirtProcr *animPr);
    6.79 +#define VMS_ext__record_time_point_into_new_probe( nameStr ) \
    6.80 +        VMS_ext_impl__record_time_point_into_new_probe_impl( nameStr )
    6.81 +
    6.82 +
    6.83 +int32
    6.84 +VMS_impl__create_single_interval_probe( char *nameStr, VirtProcr *animPr );
    6.85 +#define VMS__create_single_interval_probe( nameStr, animPr ) \
    6.86 +        VMS_impl__create_single_interval_probe( nameStr, animPr )
    6.87 +
    6.88 +
    6.89 +int32
    6.90 +VMS_impl__create_histogram_probe( int32   numBins, float64    startValue,
    6.91 +               float64 binWidth, char    *nameStr, VirtProcr *animPr );
    6.92 +#define VMS__create_histogram_probe(      numBins, startValue,              \
    6.93 +                                          binWidth, nameStr, animPr )       \
    6.94 +        VMS_impl__create_histogram_probe( numBins, startValue,              \
    6.95 +                                          binWidth, nameStr, animPr )
    6.96 +
    6.97 +void
    6.98 +VMS_impl__index_probe_by_its_name( int32 probeID, VirtProcr *animPr );
    6.99 +#define VMS__index_probe_by_its_name( probeID, animPr ) \
   6.100 +        VMS_impl__index_probe_by_its_name( probeID, animPr )
   6.101 +
   6.102 +IntervalProbe *
   6.103 +VMS_impl__get_probe_by_name( char *probeName, VirtProcr *animPr );
   6.104 +#define VMS__get_probe_by_name( probeID, animPr ) \
   6.105 +        VMS_impl__get_probe_by_name( probeName, animPr )
   6.106 +
   6.107 +void
   6.108 +VMS_impl__record_sched_choice_into_probe( int32 probeID, VirtProcr *animPr );
   6.109 +#define VMS__record_sched_choice_into_probe( probeID, animPr ) \
   6.110 +        VMS_impl__record_sched_choice_into_probe( probeID, animPr )
   6.111 +
   6.112 +void
   6.113 +VMS_impl__record_interval_start_in_probe( int32 probeID );
   6.114 +#define VMS__record_interval_start_in_probe( probeID ) \
   6.115 +        VMS_impl__record_interval_start_in_probe( probeID )
   6.116 +
   6.117 +void
   6.118 +VMS_impl__record_interval_end_in_probe( int32 probeID );
   6.119 +#define VMS__record_interval_end_in_probe( probeID ) \
   6.120 +        VMS_impl__record_interval_end_in_probe( probeID )
   6.121 +
   6.122 +void
   6.123 +VMS_impl__print_stats_of_probe( int32 probeID );
   6.124 +#define VMS__print_stats_of_probe( probeID ) \
   6.125 +        VMS_impl__print_stats_of_probe( probeID )
   6.126 +
   6.127 +void
   6.128 +VMS_impl__print_stats_of_all_probes();
   6.129 +#define VMS__print_stats_of_all_probes \
   6.130 +        VMS_impl__print_stats_of_all_probes
   6.131 +
   6.132 +
   6.133 +#else
   6.134 +int32
   6.135 +VMS_impl__record_time_point_into_new_probe( char *nameStr,VirtProcr *animPr);
   6.136 +#define VMS__record_time_point_into_new_probe( nameStr, animPr ) \
   6.137 +       0 /* do nothing */
   6.138 +
   6.139 +int32
   6.140 +VMS_ext_impl__record_time_point_into_new_probe( char *nameStr, VirtProcr *animPr);
   6.141 +#define VMS_ext__record_time_point_into_new_probe( nameStr ) \
   6.142 +       0 /* do nothing */
   6.143 +
   6.144 +
   6.145 +int32
   6.146 +VMS_impl__create_single_interval_probe( char *nameStr, VirtProcr *animPr );
   6.147 +#define VMS__create_single_interval_probe( nameStr, animPr ) \
   6.148 +       0 /* do nothing */
   6.149 +
   6.150 +
   6.151 +int32
   6.152 +VMS_impl__create_histogram_probe( int32   numBins, float64    startValue,
   6.153 +               float64 binWidth, char    *nameStr, VirtProcr *animPr );
   6.154 +#define VMS__create_histogram_probe(      numBins, startValue,              \
   6.155 +                                          binWidth, nameStr, animPr )       \
   6.156 +       0 /* do nothing */
   6.157 +
   6.158 +void
   6.159 +VMS_impl__index_probe_by_its_name( int32 probeID, VirtProcr *animPr );
   6.160 +#define VMS__index_probe_by_its_name( probeID, animPr ) \
   6.161 +        /* do nothing */
   6.162 +
   6.163 +IntervalProbe *
   6.164 +VMS_impl__get_probe_by_name( char *probeName, VirtProcr *animPr );
   6.165 +#define VMS__get_probe_by_name( probeID, animPr ) \
   6.166 +       NULL /* do nothing */
   6.167 +
   6.168 +void
   6.169 +VMS_impl__record_sched_choice_into_probe( int32 probeID, VirtProcr *animPr );
   6.170 +#define VMS__record_sched_choice_into_probe( probeID, animPr ) \
   6.171 +        /* do nothing */
   6.172 +
   6.173 +void
   6.174 +VMS_impl__record_interval_start_in_probe( int32 probeID );
   6.175 +#define VMS__record_interval_start_in_probe( probeID ) \
   6.176 +        /* do nothing */
   6.177 +
   6.178 +void
   6.179 +VMS_impl__record_interval_end_in_probe( int32 probeID );
   6.180 +#define VMS__record_interval_end_in_probe( probeID ) \
   6.181 +        /* do nothing */
   6.182 +
   6.183 +void
   6.184 +VMS_impl__print_stats_of_probe( int32 probeID );
   6.185 +#define VMS__print_stats_of_probe( probeID ) \
   6.186 +        /* do nothing */
   6.187 +
   6.188 +void
   6.189 +VMS_impl__print_stats_of_all_probes();
   6.190 +#define VMS__print_stats_of_all_probes \
   6.191 +        /* do nothing */
   6.192 +
   6.193 +#endif   /* defined STATS__ENABLE_PROBES */
   6.194 +
   6.195 +#endif	/* _PROBES_H */
   6.196 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/vmalloc.c	Sat Oct 30 20:54:36 2010 -0700
     7.3 @@ -0,0 +1,256 @@
     7.4 +/*
     7.5 + *  Copyright 2009 OpenSourceCodeStewardshipFoundation.org
     7.6 + *  Licensed under GNU General Public License version 2
     7.7 + *
     7.8 + * Author: seanhalle@yahoo.com
     7.9 + *
    7.10 + * Created on November 14, 2009, 9:07 PM
    7.11 + */
    7.12 +
    7.13 +#include <malloc.h>
    7.14 +
    7.15 +#include "VMS.h"
    7.16 +
    7.17 +/*Helper function
    7.18 + *Insert a newly generated free chunk into the first spot on the free list.
    7.19 + * The chunk is cast as a MallocProlog, so the various pointers in it are
    7.20 + * accessed with C's help -- and the size of the prolog is easily added to
    7.21 + * the pointer when a chunk is returned to the app -- so C handles changes
    7.22 + * in pointer sizes among machines.
    7.23 + *
    7.24 + *The list head is a normal MallocProlog struct -- identified by its
    7.25 + * prevChunkInFreeList being NULL -- the only one.
    7.26 + *
    7.27 + *The end of the list is identified by next chunk being NULL, as usual.
    7.28 + */
    7.29 +void inline
    7.30 +add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
    7.31 + { 
    7.32 +   chunk->nextChunkInFreeList     = listHead->nextChunkInFreeList;
    7.33 +   if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
    7.34 +      chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
    7.35 +   chunk->prevChunkInFreeList     = listHead;
    7.36 +   listHead->nextChunkInFreeList  = chunk;
    7.37 + }
    7.38 +
    7.39 +
    7.40 +/*This is sequential code, meant to only be called from the Master, not from
    7.41 + * any slave VPs.
    7.42 + *Search down list, checking size by the nextHigherInMem pointer, to find
    7.43 + * first chunk bigger than size needed.
    7.44 + *Shave off the extra and make it into a new free-list element, hook it in
    7.45 + * then return the address of the found element plus size of prolog.
    7.46 + *
    7.47 + *Will find a
    7.48 + */
    7.49 +void *
    7.50 +VMS__malloc( int32 sizeRequested )
    7.51 + { MallocProlog *foundElem = NULL, *currElem, *newElem;
    7.52 +   int32         amountExtra, foundElemIsTopOfHeap, sizeConsumed,sizeOfFound;
    7.53 +
    7.54 +      //step up the size to be aligned at 16-byte boundary, prob better ways
    7.55 +   sizeRequested = ((sizeRequested + 16) >> 4) << 4;
    7.56 +   currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
    7.57 +
    7.58 +   while( currElem != NULL )
    7.59 +    {    //check if size of currElem is big enough
    7.60 +      sizeOfFound=(int32)((char*)currElem->nextHigherInMem -(char*)currElem);
    7.61 +      amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
    7.62 +      if( amountExtra > 0 )
    7.63 +       {    //found it, get out of loop
    7.64 +         foundElem = currElem;
    7.65 +         currElem = NULL;
    7.66 +       }
    7.67 +      else
    7.68 +         currElem = currElem->nextChunkInFreeList;
    7.69 +    }
    7.70 +
    7.71 +   if( foundElem == NULL )
    7.72 +    { PRINT_ERROR("\nmalloc failed\n")
    7.73 +      return NULL;  //indicates malloc failed
    7.74 +    }
    7.75 +      //Using a kludge to identify the element that is the top chunk in the
    7.76 +      // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
    7.77 +      // save addr of start of heap in head's nextLowerInMem
    7.78 +      //Will handle top of Heap specially
    7.79 +   foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
    7.80 +                          _VMSMasterEnv->freeListHead->nextHigherInMem;
    7.81 +
    7.82 +      //before shave off and try to insert new elem, remove found elem
    7.83 +      //note, foundElem will never be the head, so always has valid prevChunk
    7.84 +   foundElem->prevChunkInFreeList->nextChunkInFreeList =
    7.85 +                                              foundElem->nextChunkInFreeList;
    7.86 +   if( foundElem->nextChunkInFreeList != NULL )
    7.87 +    { foundElem->nextChunkInFreeList->prevChunkInFreeList =
    7.88 +                                              foundElem->prevChunkInFreeList;
    7.89 +    }
    7.90 +   foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
    7.91 +   
    7.92 +      //if enough, turn extra into new elem & insert it
    7.93 +   if( amountExtra > 64 )
    7.94 +    {    //make new elem by adding to addr of curr elem then casting
    7.95 +      sizeConsumed = sizeof(MallocProlog) + sizeRequested;
    7.96 +      newElem = (MallocProlog *)( (char *)foundElem + sizeConsumed );
    7.97 +      newElem->nextHigherInMem   = foundElem->nextHigherInMem;
    7.98 +      newElem->nextLowerInMem    = foundElem;
    7.99 +      foundElem->nextHigherInMem = newElem;
   7.100 +      
   7.101 +      if( ! foundElemIsTopOfHeap )
   7.102 +       {    //there is no next higher for top of heap, so can't write to it
   7.103 +         newElem->nextHigherInMem->nextLowerInMem = newElem;
   7.104 +       }
   7.105 +      add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
   7.106 +    }
   7.107 +   else
   7.108 +    {
   7.109 +      sizeConsumed = sizeOfFound;
   7.110 +    }
   7.111 +  _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
   7.112 +
   7.113 +      //skip over the prolog by adding its size to the pointer return
   7.114 +   return (void *)((char *)foundElem + sizeof(MallocProlog));
   7.115 + }
   7.116 +
   7.117 +
   7.118 +/*This is sequential code -- only to be called from the Master
   7.119 + * When free, subtract the size of prolog from pointer, then cast it to a
   7.120 + * MallocProlog.  Then check the nextLower and nextHigher chunks to see if
   7.121 + * one or both are also free, and coalesce if so, and if neither free, then
   7.122 + * add this one to free-list.
   7.123 + */
   7.124 +void
   7.125 +VMS__free( void *ptrToFree )
   7.126 + { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
   7.127 +   int32         lowerExistsAndIsFree, higherExistsAndIsFree, sizeOfElem;
   7.128 +
   7.129 +   if( ptrToFree < _VMSMasterEnv->freeListHead->nextLowerInMem ||
   7.130 +       ptrToFree > _VMSMasterEnv->freeListHead->nextHigherInMem )
   7.131 +    {    //outside the range of data owned by VMS's malloc, so do nothing
   7.132 +      return;
   7.133 +    }
   7.134 +      //subtract size of prolog to get pointer to prolog, then cast
   7.135 +   elemToFree = (MallocProlog *)((char *)ptrToFree - sizeof(MallocProlog));
   7.136 +   sizeOfElem =(int32)((char*)elemToFree->nextHigherInMem-(char*)elemToFree);
   7.137 +   _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
   7.138 +
   7.139 +   nextLowerElem  = elemToFree->nextLowerInMem;
   7.140 +   nextHigherElem = elemToFree->nextHigherInMem;
   7.141 +
   7.142 +   if( nextHigherElem == NULL )
   7.143 +      higherExistsAndIsFree = FALSE;
   7.144 +   else //okay exists, now check if in the free-list by checking back ptr
   7.145 +      higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
   7.146 +    
   7.147 +   if( nextLowerElem == NULL )
   7.148 +      lowerExistsAndIsFree = FALSE;
   7.149 +   else //okay, it exists, now check if it's free
   7.150 +      lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
   7.151 +    
   7.152 +
   7.153 +      //now, know what exists and what's free
   7.154 +   if( lowerExistsAndIsFree )
   7.155 +    { if( higherExistsAndIsFree )
   7.156 +       {    //both exist and are free, so coalesce all three
   7.157 +            //First, remove higher from free-list
   7.158 +         nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
   7.159 +                                         nextHigherElem->nextChunkInFreeList;
   7.160 +         if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
   7.161 +            nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
   7.162 +                                         nextHigherElem->prevChunkInFreeList;
   7.163 +            //Now, fix-up sequence-in-mem list -- by side-effect, this also
   7.164 +            // changes size of the lower elem, which is still in free-list
   7.165 +         nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
   7.166 +         if( nextHigherElem->nextHigherInMem !=
   7.167 +             _VMSMasterEnv->freeListHead->nextHigherInMem )
   7.168 +            nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
   7.169 +            //notice didn't do anything to elemToFree -- it simply is no
   7.170 +            // longer reachable from any of the lists.  Wonder if could be a
   7.171 +            // security leak because left valid addresses in it,
   7.172 +            // but don't care for now.
   7.173 +       }
   7.174 +      else
   7.175 +       {    //lower is the only of the two that exists and is free,
   7.176 +            //In this case, no adjustment to free-list, just change mem-list.
   7.177 +            // By side-effect, changes size of the lower elem
   7.178 +         nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
   7.179 +         if( elemToFree->nextHigherInMem !=
   7.180 +             _VMSMasterEnv->freeListHead->nextHigherInMem )
   7.181 +            elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
   7.182 +       }
   7.183 +    }
   7.184 +   else
   7.185 +    {    //lower either doesn't exist or isn't free, so check higher
   7.186 +      if( higherExistsAndIsFree )
   7.187 +       {    //higher exists and is the only of the two free
   7.188 +            //First, in free-list, replace higher elem with the one to free
   7.189 +         elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
   7.190 +         elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
   7.191 +         elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
   7.192 +         if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
   7.193 +            elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
   7.194 +            //Now chg mem-list. By side-effect, changes size of elemToFree
   7.195 +         elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
   7.196 +         if( elemToFree->nextHigherInMem !=
   7.197 +             _VMSMasterEnv->freeListHead->nextHigherInMem )
   7.198 +            elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
   7.199 +       }
   7.200 +      else
   7.201 +       {    //neither lower nor higher is availabe to coalesce so add to list
   7.202 +            // this makes prev chunk ptr non-null, which indicates it's free
   7.203 +         elemToFree->nextChunkInFreeList =
   7.204 +                            _VMSMasterEnv->freeListHead->nextChunkInFreeList;
   7.205 +         _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
   7.206 +         if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
   7.207 +            elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
   7.208 +         elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
   7.209 +       }
   7.210 +    }
   7.211 +
   7.212 + }
   7.213 +
   7.214 +
   7.215 +/*Designed to be called from the main thread outside of VMS, during init
   7.216 + */
   7.217 +MallocProlog *
   7.218 +VMS__create_free_list()
   7.219 + { MallocProlog *freeListHead, *firstChunk;
   7.220 +
   7.221 +      //Note, this is running in the main thread -- all increases in malloc
   7.222 +      // mem and all frees of it must be done in this thread, with the
   7.223 +      // thread's original stack available
   7.224 +   freeListHead = malloc( sizeof(MallocProlog) );
   7.225 +   firstChunk   = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
   7.226 +   if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
   7.227 +
   7.228 +   freeListHead->prevChunkInFreeList = NULL;
   7.229 +      //Use this addr to free the heap when cleanup
   7.230 +   freeListHead->nextLowerInMem      = firstChunk;
   7.231 +      //to identify top-of-heap elem, compare this addr to elem's next higher
   7.232 +   freeListHead->nextHigherInMem     = (char *)firstChunk +
   7.233 +                                          MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
   7.234 +   freeListHead->nextChunkInFreeList = firstChunk;
   7.235 +
   7.236 +   firstChunk->nextChunkInFreeList   = NULL;
   7.237 +   firstChunk->prevChunkInFreeList   = freeListHead;
   7.238 +      //next Higher has to be set to top of chunk, so can calc size in malloc
   7.239 +   firstChunk->nextHigherInMem       = (char *)firstChunk +
   7.240 +                                          MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
   7.241 +   firstChunk->nextLowerInMem        = NULL; //identifies as bott of heap
   7.242 +
   7.243 +   return freeListHead;
   7.244 + }
   7.245 +
   7.246 +
   7.247 +/*Designed to be called from the main thread outside of VMS, during cleanup
   7.248 + */
   7.249 +void
   7.250 +VMS_ext__free_free_list( MallocProlog *freeListHead )
   7.251 + {    
   7.252 +      //stashed a ptr to the one and only bug chunk malloc'd from OS in the
   7.253 +      // free list head's next lower in mem pointer
   7.254 +   free( freeListHead->nextLowerInMem );
   7.255 +
   7.256 +   //don't free the head -- it'll be in an array eventually -- free whole
   7.257 +   // array when all the free lists linked from it have already been freed
   7.258 + }
   7.259 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/vmalloc.h	Sat Oct 30 20:54:36 2010 -0700
     8.3 @@ -0,0 +1,41 @@
     8.4 +/*
     8.5 + *  Copyright 2009 OpenSourceCodeStewardshipFoundation.org
     8.6 + *  Licensed under GNU General Public License version 2
     8.7 + *
     8.8 + * Author: seanhalle@yahoo.com
     8.9 + *
    8.10 + * Created on November 14, 2009, 9:07 PM
    8.11 + */
    8.12 +
    8.13 +#include <malloc.h>
    8.14 +#include "VMS_primitive_data_types.h"
    8.15 +
    8.16 +typedef struct _MallocProlog MallocProlog;
    8.17 +
    8.18 +struct _MallocProlog
    8.19 + {
    8.20 +   MallocProlog *nextChunkInFreeList;
    8.21 +   MallocProlog *prevChunkInFreeList;
    8.22 +   MallocProlog *nextHigherInMem;
    8.23 +   MallocProlog *nextLowerInMem;
    8.24 + };
    8.25 +//MallocProlog
    8.26 +
    8.27 +typedef struct
    8.28 + {
    8.29 +   MallocProlog *firstChunkInFreeList;
    8.30 +   int32         numInList;
    8.31 + }
    8.32 +FreeListHead;
    8.33 +
    8.34 +void *
    8.35 +VMS__malloc( int32 sizeRequested );
    8.36 +
    8.37 +void
    8.38 +VMS__free( void *ptrToFree );
    8.39 +
    8.40 +MallocProlog *
    8.41 +VMS__create_free_list();
    8.42 +
    8.43 +void
    8.44 +VMS_ext__free_free_list( MallocProlog *freeListHead );