# HG changeset patch # User Merten Sach # Date 1316175949 -7200 # Node ID dbfc8382d5462871e61f664a2da585db52491cb8 # Parent 24466227d8bbf0b251751edeb53e53248ada14b8 distributed memory allocation interface - unfinished diff -r 24466227d8bb -r dbfc8382d546 CoreLoop.c --- a/CoreLoop.c Wed Sep 07 17:45:05 2011 +0200 +++ b/CoreLoop.c Fri Sep 16 14:25:49 2011 +0200 @@ -70,7 +70,6 @@ //Designate a core by a 1 in bit-position corresponding to the core CPU_ZERO(&coreMask); CPU_SET(coreLoopThdParams->coreNum,&coreMask); - //coreMask = 1L << coreLoopThdParams->coreNum; pthread_t selfThd = pthread_self(); errorCode = diff -r 24466227d8bb -r dbfc8382d546 MasterLoop.c --- a/MasterLoop.c Wed Sep 07 17:45:05 2011 +0200 +++ b/MasterLoop.c Fri Sep 16 14:25:49 2011 +0200 @@ -94,6 +94,7 @@ volatileMasterPr = animatingPr; masterPr = (VirtProcr*)volatileMasterPr; //used to force re-define after jmp + masterEnv = (MasterEnv*)_VMSMasterEnv; //First animation of each MasterVP will in turn animate this part // of setup code.. (VP creator sets up the stack as if this function @@ -104,8 +105,7 @@ // So, just make this an endless loop, and do assembly function at end // that saves its own return addr, then jumps to core_loop. while(1) - { - + { //============================= MEASUREMENT STUFF ======================== #ifdef MEAS__TIME_MASTER //Total Master time includes one coreloop time -- just assume the core @@ -115,11 +115,9 @@ #endif //======================================================================== - masterEnv = (MasterEnv*)_VMSMasterEnv; - - //GCC may optimize so doesn't always re-define from frame-storage - masterPr = (VirtProcr*)volatileMasterPr; //on stack, reload after jmp + //GCC may optimize so doesn't always re-define from frame-storage thisCoresIdx = masterPr->coreAnimatedBy; + masterEnv->currentMasterProcrID = thisCoresIdx; readyToAnimateQ = masterEnv->readyToAnimateQs[thisCoresIdx]; schedSlots = masterEnv->allSchedSlots[thisCoresIdx]; @@ -174,6 +172,7 @@ if( schedVirtPr != NULL ) { currSlot->procrAssignedToSlot = schedVirtPr; schedVirtPr->schedSlot = currSlot; + schedVirtPr->coreAnimatedBy = thisCoresIdx; currSlot->needsProcrAssigned = FALSE; numSlotsFilled += 1; diff -r 24466227d8bb -r dbfc8382d546 ProcrContext.h --- a/ProcrContext.h Wed Sep 07 17:45:05 2011 +0200 +++ b/ProcrContext.h Fri Sep 16 14:25:49 2011 +0200 @@ -5,11 +5,60 @@ * Author: seanhalle@yahoo.com * */ - #ifndef _ProcrContext_H #define _ProcrContext_H #define _GNU_SOURCE +#include "VMS.h" + +typedef struct _SchedSlot SchedSlot; +typedef struct _VirtProcr VirtProcr; + +/*WARNING: re-arranging this data structure could cause VP switching + * assembly code to fail -- hard-codes offsets of fields + */ +struct _VirtProcr + { int procrID; //for debugging -- count up each time create + int coreAnimatedBy; + void *startOfStack; + void *stackPtr; + void *framePtr; + void *nextInstrPt; + + void *coreLoopStartPt; //allows proto-runtime to be linked later + void *coreLoopFramePtr; //restore before jmp back to core loop + void *coreLoopStackPtr; //restore before jmp back to core loop + + void *initialData; + + SchedSlot *schedSlot; + VMSReqst *requests; + + void *semanticData; + void *dataRetFromReq; //values returned from plugin to VP go here + + //=========== MEASUREMENT STUFF ========== + #ifdef MEAS__TIME_STAMP_SUSP + unsigned int preSuspTSCLow; + unsigned int postSuspTSCLow; + #endif + #ifdef MEAS__TIME_MASTER /* in VirtProcr because multiple masterVPs*/ + unsigned int startMasterTSCLow;USE_GNU + unsigned int endMasterTSCLow; + #endif + //======================================== + + float64 createPtInSecs; //have space but don't use on some configs + }; +//VirtProcr + +struct _SchedSlot + { + int workIsDone; + int needsProcrAssigned; + VirtProcr *procrAssignedToSlot; + }; + void saveCoreLoopReturnAddr(void **returnAddress); void switchToVP(VirtProcr *nextProcr); diff -r 24466227d8bb -r dbfc8382d546 VMS.c --- a/VMS.c Wed Sep 07 17:45:05 2011 +0200 +++ b/VMS.c Fri Sep 16 14:25:49 2011 +0200 @@ -105,7 +105,11 @@ //Very first thing put into the master env is the free-list, seeded // with a massive initial chunk of memory. //After this, all other mallocs are VMS__malloc. - _VMSMasterEnv->freeListHead = VMS_ext__create_free_list(); + int i; + for(i=0; ifreeListHead[i] = VMS_ext__create_free_list(); + } //============================= MEASUREMENT STUFF ======================== diff -r 24466227d8bb -r dbfc8382d546 VMS.h --- a/VMS.h Wed Sep 07 17:45:05 2011 +0200 +++ b/VMS.h Fri Sep 16 14:25:49 2011 +0200 @@ -5,7 +5,6 @@ * Author: seanhalle@yahoo.com * */ - #ifndef _VMS_H #define _VMS_H #define _GNU_SOURCE @@ -111,9 +110,7 @@ //=========================================================================== typedef unsigned long long TSCount; -typedef struct _SchedSlot SchedSlot; typedef struct _VMSReqst VMSReqst; -typedef struct _VirtProcr VirtProcr; typedef struct _InterMasterReqst InterMasterReqst; typedef struct _IntervalProbe IntervalProbe; typedef struct _GateStruc GateStruc; @@ -215,53 +212,6 @@ //==================== Core data structures =================== -struct _SchedSlot - { - int workIsDone; - int needsProcrAssigned; - VirtProcr *procrAssignedToSlot; - }; -//SchedSlot - -/*WARNING: re-arranging this data structure could cause VP switching - * assembly code to fail -- hard-codes offsets of fields - */ -struct _VirtProcr - { int procrID; //for debugging -- count up each time create - int coreAnimatedBy; - void *startOfStack; - void *stackPtr; - void *framePtr; - void *nextInstrPt; - - void *coreLoopStartPt; //allows proto-runtime to be linked later - void *coreLoopFramePtr; //restore before jmp back to core loop - void *coreLoopStackPtr; //restore before jmp back to core loop - - void *initialData; - - SchedSlot *schedSlot; - VMSReqst *requests; - - void *semanticData; //this livesUSE_GNU here for the life of VP - void *dataRetFromReq;//values returned from plugin to VP go here - - //=========== MEASUREMENT STUFF ========== - #ifdef MEAS__TIME_STAMP_SUSP - unsigned int preSuspTSCLow; - unsigned int postSuspTSCLow; - #endif - #ifdef MEAS__TIME_MASTER /* in VirtProcr because multiple masterVPs*/ - unsigned int startMasterTSCLow;USE_GNU - unsigned int endMasterTSCLow; - #endif - //======================================== - - float64 createPtInSecs; //have space but don't use on some configs - }; -//VirtProcr - - /*Master Env is the only global variable -- has entry points for any other * data needed. */ @@ -276,22 +226,25 @@ void *semanticEnv; void *OSEventStruc; //for future, when add I/O to BLIS - MallocProlog *freeListHead; - int32 amtOfOutstandingMem; //total currently allocated void *coreLoopReturnPt;//addr to jump to to re-enter coreLoop int32 setupComplete; volatile int32 masterLock; + + MallocProlog *freeListHead[NUM_CORES]; + int32 amtOfOutstandingMem; //total currently allocated int32 numMasterInARow[NUM_CORES];//detect back-to-back masterVP - GateStruc *workStealingGates[ NUM_CORES ]; //concurrent work-steal + GateStruc *workStealingGates[NUM_CORES]; //concurrent work-steal int32 workStealingLock; InterMasterReqst* interMasterRequestsFor[NUM_CORES]; RequestHandler interPluginReqHdlr; int32 numProcrsCreated; //gives ordering to processor creation + + int32 currentMasterProcrID; //=========== MEASUREMENT STUFF ============= IntervalProbe **intervalProbes; diff -r 24466227d8bb -r dbfc8382d546 contextSwitch.s --- a/contextSwitch.s Wed Sep 07 17:45:05 2011 +0200 +++ b/contextSwitch.s Fri Sep 16 14:25:49 2011 +0200 @@ -2,7 +2,17 @@ .text - +/* VirtProcr offsets: + * 0x10 stackPtr + * 0x18 framePtr + * 0x20 nextInstrPt + * 0x30 coreLoopFramePtr + * 0x38 coreLoopStackPtr + * + * _VMSMasterEnv offsets: + * 0x38 coreLoopReturnPt + * 0x44 masterLock + */ //Save return label address for the coreLoop to pointer //Arguments: Pointer to variable holding address .globl saveCoreLoopReturnAddr @@ -23,17 +33,6 @@ //Switches form CoreLoop to VP ether a normal VP or the Master Loop //switch to virt procr's stack and frame ptr then jump to virt procr fn -/* VirtProcr offsets: - * 0x10 stackPtr - * 0x18 framePtr - * 0x20 nextInstrPt - * 0x30 coreLoopFramePtr - * 0x38 coreLoopStackPtr - * - * _VMSMasterEnv offsets: - * 0x48 coreLoopReturnPt - * 0x54 masterLock - */ .globl switchToVP switchToVP: #VirtProcr in %rdi @@ -48,17 +47,6 @@ //switches to core loop. saves return address -/* VirtProcr offsets: - * 0x10 stackPtr - * 0x18 framePtr - * 0x20 nextInstrPt - * 0x30 coreLoopFramePtr - * 0x38 coreLoopStackPtr - * - * _VMSMasterEnv offsets: - * 0x48 coreLoopReturnPt - * 0x54 masterLock - */ .globl switchToCoreLoop switchToCoreLoop: #VirtProcr in %rdi @@ -69,7 +57,7 @@ movq 0x30(%rdi), %rbp #restore frame pointer movq $_VMSMasterEnv, %rcx movq (%rcx) , %rcx - movq 0x48(%rcx), %rax #get CoreLoopStartPt + movq 0x38(%rcx), %rax #get CoreLoopStartPt jmp *%rax #jmp to CoreLoop VPReturn: ret @@ -78,17 +66,6 @@ //switches to core loop from master. saves return address //Releases masterLock so the next MasterLoop can be executed -/* VirtProcr offsets: - * 0x10 stackPtr - * 0x18 framePtr - * 0x20 nextInstrPt - * 0x30 coreLoopFramePtr - * 0x38 coreLoopStackPtr - * - * _VMSMasterEnv offsets: - * 0x48 coreLoopReturnPt - * 0x54 masterLock - */ .globl masterSwitchToCoreLoop masterSwitchToCoreLoop: #VirtProcr in %rdi @@ -99,8 +76,8 @@ movq 0x30(%rdi), %rbp #restore frame pointer movq $_VMSMasterEnv, %rcx movq (%rcx) , %rcx - movq 0x48(%rcx), %rax #get CoreLoopStartPt - movl $0x0 , 0x54(%rcx) #release lock + movq 0x38(%rcx), %rax #get CoreLoopStartPt + movl $0x0 , 0x44(%rcx) #release lock jmp *%rax #jmp to CoreLoop MasterReturn: ret @@ -112,17 +89,6 @@ // and virtPr is in %rdi // and both functions have the same argument. // do not save register of VP because this function will never return -/* VirtProcr offsets: - * 0x10 stackPtr - * 0x18 framePtr - * 0x20 nextInstrPt - * 0x30 coreLoopFramePtr - * 0x38 coreLoopStackPtr - * - * _VMSMasterEnv offsets: - * 0x48 coreLoopReturnPt - * 0x58 masterLock - */ .globl asmTerminateCoreLoop asmTerminateCoreLoop: #VirtProcr in %rdi diff -r 24466227d8bb -r dbfc8382d546 vmalloc.c --- a/vmalloc.c Wed Sep 07 17:45:05 2011 +0200 +++ b/vmalloc.c Fri Sep 16 14:25:49 2011 +0200 @@ -12,7 +12,7 @@ #include #include -#include "VMS.h" +#include "ProcrContext.h" #include "Histogram/Histogram.h" /*Helper function @@ -37,18 +37,37 @@ listHead->nextChunkInFreeList = chunk; } +/* + * This function is called by code which is part of the master loop. + * This reads the animating coreID from the MasterEnv and calls the normal malloc + * in VMS__malloc_on_core + */ +void * +VMS__malloc( size_t sizeRequested) +{ + return VMS__malloc_on_core(sizeRequested, _VMSMasterEnv->currentMasterProcrID); +} -/*This is sequential code, meant to only be called from the Master, not from - * any slave VPs. +/* + * This is called by the plugin. This call to VMS_malloc_on_core is run on the + * slave VPs stack so there is no switch to the VMS runtime. + */ +void * +VMS__malloc_in_lib(size_t sizeRequested, VirtProcr *VProcr) +{ + return VMS__malloc_on_core(sizeRequested, VProcr->coreAnimatedBy); +} + +/* *Search down list, checking size by the nextHigherInMem pointer, to find * first chunk bigger than size needed. *Shave off the extra and make it into a new free-list element, hook it in * then return the address of the found element plus size of prolog. - * - *Will find a */ -void *VMS__malloc( size_t sizeRequested ) +void * +VMS__malloc_on_core( size_t sizeRequested, int procrID) { MallocProlog *foundElem = NULL, *currElem, *newElem; + MallocPrologAllocated *returnElem; ssize_t amountExtra, sizeConsumed,sizeOfFound; uint32 foundElemIsTopOfHeap; @@ -61,7 +80,8 @@ //step up the size to be aligned at 16-byte boundary, prob better ways sizeRequested = (sizeRequested + 16) & ~15; - currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; + currElem = (_VMSMasterEnv->freeListHead[_VMSMasterEnv->currentMasterProcrID]) + ->nextChunkInFreeList; while( currElem != NULL ) { //check if size of currElem is big enough @@ -95,16 +115,18 @@ { foundElem->nextChunkInFreeList->prevChunkInFreeList = foundElem->prevChunkInFreeList; } - foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated + returnElem = (MallocPrologAllocated*)foundElem; + returnElem->prevChunkInFreeList = NULL;//indicates elem currently allocated + returnElem->procrID = procrID; //if enough, turn extra into new elem & insert it if( amountExtra > 64 ) { //make new elem by adding to addr of curr elem then casting sizeConsumed = sizeof(MallocProlog) + sizeRequested; - newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); - newElem->nextLowerInMem = foundElem; //This is evil (but why?) - newElem->nextHigherInMem = foundElem->nextHigherInMem; //This is evil (but why?) - foundElem->nextHigherInMem = newElem; + newElem = (MallocProlog *)( (uintptr_t)returnElem + sizeConsumed ); + newElem->nextLowerInMem = returnElem; //This is evil (but why?) + newElem->nextHigherInMem = returnElem->nextHigherInMem; //This is evil (but why?) + returnElem->nextHigherInMem = newElem; if( ! foundElemIsTopOfHeap ) { //there is no next higher for top of heap, so can't write to it newElem->nextHigherInMem->nextLowerInMem = newElem; @@ -125,139 +147,46 @@ //======================================================================== //skip over the prolog by adding its size to the pointer return - return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); + return (void*)((uintptr_t)returnElem + sizeof(MallocProlog)); } -/*This is sequential code, meant to only be called from the Master, not from - * any slave VPs. - *Search down list, checking size by the nextHigherInMem pointer, to find - * first chunk bigger than size needed. - *Shave off the extra and make it into a new free-list element, hook it in - * then return the address of the found element plus size of prolog. - * - * The difference to the regular malloc is, that all the allocated chunks are - * aligned and padded to the size of a CACHE_LINE. Thus creating a new chunk - * before the aligned chunk. +/* + * This free is called for a master loop. It decides whether the allocation of + * chunk was done on the same core. If it was it calls VMS__free_on_core + * otherwise it sends a message to the responsible core. */ -void *VMS__malloc_aligned( size_t sizeRequested ) - { MallocProlog *foundElem = NULL, *currElem, *newElem; - ssize_t amountExtra, sizeConsumed,sizeOfFound,prevAmount; - uint32 foundElemIsTopOfHeap; +void +VMS__free(void *ptrToFree) +{ + MallocPrologAllocated chunk = (MallocPrologAllocated*)ptrToFree - 1; + if(chunk->procrID == _VMSMasterEnv->currentMasterProcrID) + { + VMS__free_on_core(ptrToFree, _VMSMasterEnv->currentMasterProcrID); + } + else + { + //Request from other Core + } +} - //============================= MEASUREMENT STUFF ======================== - #ifdef MEAS__TIME_MALLOC - uint32 startStamp, endStamp; - saveLowTimeStampCountInto( startStamp ); - #endif - //======================================================================== - - //step up the size to be multiple of the cache line size - sizeRequested = (sizeRequested + CACHE_LINE) & ~(CACHE_LINE-1); - currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; - - while( currElem != NULL ) - { //check if size of currElem is big enough - sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); - amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); - if( amountExtra > 0 ) - { - //look if the found element is already aligned - if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE-1)) == 0){ - //found it, get out of loop - foundElem = currElem; - break; - }else{ - //find first aligned address and check if it's still big enough - //check also if the space before the aligned address is big enough - //for a new element - void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE) & ~((uintptr_t)(CACHE_LINE-1))); - prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem; - sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog); - amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog); - if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){ - //found suitable element - //create new previous element and exit loop - MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1; - - //insert new element into free list - if(currElem->nextChunkInFreeList != NULL) - currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem; - newAlignedElem->prevChunkInFreeList = currElem; - newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList; - currElem->nextChunkInFreeList = newAlignedElem; - - //set higherInMem and lowerInMem - newAlignedElem->nextHigherInMem = currElem->nextHigherInMem; - foundElemIsTopOfHeap = currElem->nextHigherInMem == - _VMSMasterEnv->freeListHead->nextHigherInMem; - if(!foundElemIsTopOfHeap) - currElem->nextHigherInMem->nextLowerInMem = newAlignedElem; - currElem->nextHigherInMem = newAlignedElem; - newAlignedElem->nextLowerInMem = currElem; - - //Found new element leaving loop - foundElem = newAlignedElem; - break; - } - } - - } - currElem = currElem->nextChunkInFreeList; +/* + * This free is called for the plugins. It decides whether the allocation of + * chunk was done on the same core. If it was it calls VMS__free_on_core + * otherwise it sends a message to the responsible core. + */ +void +VMS__free_in_lib(void *ptrToFree, VirtProcr *VProc) +{ + MallocPrologAllocated chunk = (MallocPrologAllocated*)ptrToFree - 1; + if(chunk->procrID == VProc->coreAnimatedBy) + { + VMS__free_on_core(ptrToFree, VProc->coreAnimatedBy); } - - if( foundElem == NULL ) - { ERROR("\nmalloc failed\n") - return (void *)NULL; //indicates malloc failed + else + { + //Request from other Core } - //Using a kludge to identify the element that is the top chunk in the - // heap -- saving top-of-heap addr in head's nextHigherInMem -- and - // save addr of start of heap in head's nextLowerInMem - //Will handle top of Heap specially - foundElemIsTopOfHeap = foundElem->nextHigherInMem == - _VMSMasterEnv->freeListHead->nextHigherInMem; - - //before shave off and try to insert new elem, remove found elem - //note, foundElem will never be the head, so always has valid prevChunk - foundElem->prevChunkInFreeList->nextChunkInFreeList = - foundElem->nextChunkInFreeList; - if( foundElem->nextChunkInFreeList != NULL ) - { foundElem->nextChunkInFreeList->prevChunkInFreeList = - foundElem->prevChunkInFreeList; - } - foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated - - //if enough, turn extra into new elem & insert it - if( amountExtra > 64 ) - { //make new elem by adding to addr of curr elem then casting - sizeConsumed = sizeof(MallocProlog) + sizeRequested; - newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); - newElem->nextHigherInMem = foundElem->nextHigherInMem; - newElem->nextLowerInMem = foundElem; - foundElem->nextHigherInMem = newElem; - - if( ! foundElemIsTopOfHeap ) - { //there is no next higher for top of heap, so can't write to it - newElem->nextHigherInMem->nextLowerInMem = newElem; - } - add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); - } - else - { - sizeConsumed = sizeOfFound; - } - _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; - - //============================= MEASUREMENT STUFF ======================== - #ifdef MEAS__TIME_MALLOC - saveLowTimeStampCountInto( endStamp ); - addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); - #endif - //======================================================================== - - //skip over the prolog by adding its size to the pointer return - return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); - } - +} /*This is sequential code -- only to be called from the Master * When free, subtract the size of prolog from pointer, then cast it to a @@ -266,7 +195,7 @@ * add this one to free-list. */ void -VMS__free( void *ptrToFree ) +VMS__free_on_core( void *ptrToFree, int procrID) { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; size_t sizeOfElem; uint32 lowerExistsAndIsFree, higherExistsAndIsFree; @@ -443,7 +372,7 @@ MallocProlog * VMS_ext__create_free_list() { MallocProlog *freeListHead, *firstChunk; - + //Note, this is running in the main thread -- all increases in malloc // mem and all frees of it must be done in this thread, with the // thread's original stack available diff -r 24466227d8bb -r dbfc8382d546 vmalloc.h --- a/vmalloc.h Wed Sep 07 17:45:05 2011 +0200 +++ b/vmalloc.h Fri Sep 16 14:25:49 2011 +0200 @@ -6,13 +6,13 @@ * * Created on November 14, 2009, 9:07 PM */ - #ifndef _VMALLOC_H #define _VMALLOC_H #include #include #include "VMS_primitive_data_types.h" +#include "ProcrContext.h" typedef struct _MallocProlog MallocProlog; @@ -22,25 +22,41 @@ MallocProlog *prevChunkInFreeList; MallocProlog *nextHigherInMem; MallocProlog *nextLowerInMem; - }; + }; //MallocProlog + + typedef struct + { + uintptr_t procrID; + MallocProlog *prevChunkInFreeList; + MallocProlog *nextHigherInMem; + MallocProlog *nextLowerInMem; + } MallocPrologAllocated; typedef struct { MallocProlog *firstChunkInFreeList; int32 numInList; //TODO not used - } -FreeListHead; + } FreeListHead; void * -VMS__malloc( size_t sizeRequested ); +VMS__malloc_on_core(size_t sizeRequested, int procrID); void * -VMS__malloc_aligned( size_t sizeRequested ); +VMS__malloc(size_t sizeRequested); + +void * +VMS__malloc_in_lib(size_t sizeRequested, VirtProcr *VProc); void VMS__free( void *ptrToFree ); +void +VMS__free_in_lib(void *ptrToFree, VirtProcr *VProc); + +void +VMS__free_on_core(void *ptrToFree, int procrID); + /*Allocates memory from the external system -- higher overhead */ void *