Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
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 );
