Mercurial > cgi-bin > hgwebdir.cgi > VMS > VMS_Implementations > VMS_impls > VMS__MC_shared_impl
comparison vmalloc.c @ 133:3a295609f045
merged tangling head
| author | Merten Sach <msach@mailbox.tu-berlin.de> |
|---|---|
| date | Fri, 16 Sep 2011 14:26:18 +0200 |
| parents | 21c95d402fe6 |
| children | a9b72021f053 |
comparison
equal
deleted
inserted
replaced
| 12:a0b38c64a0b6 | 21:2ea90c770565 |
|---|---|
| 10 #include <malloc.h> | 10 #include <malloc.h> |
| 11 #include <inttypes.h> | 11 #include <inttypes.h> |
| 12 #include <stdlib.h> | 12 #include <stdlib.h> |
| 13 #include <stdio.h> | 13 #include <stdio.h> |
| 14 | 14 |
| 15 #include "VMS.h" | 15 #include "ProcrContext.h" |
| 16 #include "Histogram/Histogram.h" | 16 #include "Histogram/Histogram.h" |
| 17 | 17 |
| 18 /*Helper function | 18 /*Helper function |
| 19 *Insert a newly generated free chunk into the first spot on the free list. | 19 *Insert a newly generated free chunk into the first spot on the free list. |
| 20 * The chunk is cast as a MallocProlog, so the various pointers in it are | 20 * The chunk is cast as a MallocProlog, so the various pointers in it are |
| 35 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk; | 35 chunk->nextChunkInFreeList->prevChunkInFreeList = chunk; |
| 36 chunk->prevChunkInFreeList = listHead; | 36 chunk->prevChunkInFreeList = listHead; |
| 37 listHead->nextChunkInFreeList = chunk; | 37 listHead->nextChunkInFreeList = chunk; |
| 38 } | 38 } |
| 39 | 39 |
| 40 | 40 /* |
| 41 /*This is sequential code, meant to only be called from the Master, not from | 41 * This function is called by code which is part of the master loop. |
| 42 * any slave VPs. | 42 * This reads the animating coreID from the MasterEnv and calls the normal malloc |
| 43 * in VMS__malloc_on_core | |
| 44 */ | |
| 45 void * | |
| 46 VMS__malloc( size_t sizeRequested) | |
| 47 { | |
| 48 return VMS__malloc_on_core(sizeRequested, _VMSMasterEnv->currentMasterProcrID); | |
| 49 } | |
| 50 | |
| 51 /* | |
| 52 * This is called by the plugin. This call to VMS_malloc_on_core is run on the | |
| 53 * slave VPs stack so there is no switch to the VMS runtime. | |
| 54 */ | |
| 55 void * | |
| 56 VMS__malloc_in_lib(size_t sizeRequested, VirtProcr *VProcr) | |
| 57 { | |
| 58 return VMS__malloc_on_core(sizeRequested, VProcr->coreAnimatedBy); | |
| 59 } | |
| 60 | |
| 61 /* | |
| 43 *Search down list, checking size by the nextHigherInMem pointer, to find | 62 *Search down list, checking size by the nextHigherInMem pointer, to find |
| 44 * first chunk bigger than size needed. | 63 * first chunk bigger than size needed. |
| 45 *Shave off the extra and make it into a new free-list element, hook it in | 64 *Shave off the extra and make it into a new free-list element, hook it in |
| 46 * then return the address of the found element plus size of prolog. | 65 * then return the address of the found element plus size of prolog. |
| 47 * | 66 */ |
| 48 *Will find a | 67 void * |
| 49 */ | 68 VMS__malloc_on_core( size_t sizeRequested, int procrID) |
| 50 void *VMS__malloc( size_t sizeRequested ) | |
| 51 { MallocProlog *foundElem = NULL, *currElem, *newElem; | 69 { MallocProlog *foundElem = NULL, *currElem, *newElem; |
| 70 MallocPrologAllocated *returnElem; | |
| 52 ssize_t amountExtra, sizeConsumed,sizeOfFound; | 71 ssize_t amountExtra, sizeConsumed,sizeOfFound; |
| 53 uint32 foundElemIsTopOfHeap; | 72 uint32 foundElemIsTopOfHeap; |
| 54 | 73 |
| 55 //============================= MEASUREMENT STUFF ======================== | 74 //============================= MEASUREMENT STUFF ======================== |
| 56 #ifdef MEAS__TIME_MALLOC | 75 #ifdef MEAS__TIME_MALLOC |
| 59 #endif | 78 #endif |
| 60 //======================================================================== | 79 //======================================================================== |
| 61 | 80 |
| 62 //step up the size to be aligned at 16-byte boundary, prob better ways | 81 //step up the size to be aligned at 16-byte boundary, prob better ways |
| 63 sizeRequested = (sizeRequested + 16) & ~15; | 82 sizeRequested = (sizeRequested + 16) & ~15; |
| 64 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; | 83 currElem = (_VMSMasterEnv->freeListHead[_VMSMasterEnv->currentMasterProcrID]) |
| 84 ->nextChunkInFreeList; | |
| 65 | 85 |
| 66 while( currElem != NULL ) | 86 while( currElem != NULL ) |
| 67 { //check if size of currElem is big enough | 87 { //check if size of currElem is big enough |
| 68 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); | 88 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); |
| 69 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); | 89 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); |
| 93 foundElem->nextChunkInFreeList; | 113 foundElem->nextChunkInFreeList; |
| 94 if( foundElem->nextChunkInFreeList != NULL ) | 114 if( foundElem->nextChunkInFreeList != NULL ) |
| 95 { foundElem->nextChunkInFreeList->prevChunkInFreeList = | 115 { foundElem->nextChunkInFreeList->prevChunkInFreeList = |
| 96 foundElem->prevChunkInFreeList; | 116 foundElem->prevChunkInFreeList; |
| 97 } | 117 } |
| 98 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated | 118 returnElem = (MallocPrologAllocated*)foundElem; |
| 119 returnElem->prevChunkInFreeList = NULL;//indicates elem currently allocated | |
| 120 returnElem->procrID = procrID; | |
| 99 | 121 |
| 100 //if enough, turn extra into new elem & insert it | 122 //if enough, turn extra into new elem & insert it |
| 101 if( amountExtra > 64 ) | 123 if( amountExtra > 64 ) |
| 102 { //make new elem by adding to addr of curr elem then casting | 124 { //make new elem by adding to addr of curr elem then casting |
| 103 sizeConsumed = sizeof(MallocProlog) + sizeRequested; | 125 sizeConsumed = sizeof(MallocProlog) + sizeRequested; |
| 104 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); | 126 newElem = (MallocProlog *)( (uintptr_t)returnElem + sizeConsumed ); |
| 105 newElem->nextLowerInMem = foundElem; //This is evil (but why?) | 127 newElem->nextLowerInMem = returnElem; //This is evil (but why?) |
| 106 newElem->nextHigherInMem = foundElem->nextHigherInMem; //This is evil (but why?) | 128 newElem->nextHigherInMem = returnElem->nextHigherInMem; //This is evil (but why?) |
| 107 foundElem->nextHigherInMem = newElem; | 129 returnElem->nextHigherInMem = newElem; |
| 108 if( ! foundElemIsTopOfHeap ) | 130 if( ! foundElemIsTopOfHeap ) |
| 109 { //there is no next higher for top of heap, so can't write to it | 131 { //there is no next higher for top of heap, so can't write to it |
| 110 newElem->nextHigherInMem->nextLowerInMem = newElem; | 132 newElem->nextHigherInMem->nextLowerInMem = newElem; |
| 111 } | 133 } |
| 112 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); | 134 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); |
| 123 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); | 145 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); |
| 124 #endif | 146 #endif |
| 125 //======================================================================== | 147 //======================================================================== |
| 126 | 148 |
| 127 //skip over the prolog by adding its size to the pointer return | 149 //skip over the prolog by adding its size to the pointer return |
| 128 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); | 150 return (void*)((uintptr_t)returnElem + sizeof(MallocProlog)); |
| 129 } | 151 } |
| 130 | 152 |
| 131 /*This is sequential code, meant to only be called from the Master, not from | 153 /* |
| 132 * any slave VPs. | 154 * This free is called for a master loop. It decides whether the allocation of |
| 133 *Search down list, checking size by the nextHigherInMem pointer, to find | 155 * chunk was done on the same core. If it was it calls VMS__free_on_core |
| 134 * first chunk bigger than size needed. | 156 * otherwise it sends a message to the responsible core. |
| 135 *Shave off the extra and make it into a new free-list element, hook it in | 157 */ |
| 136 * then return the address of the found element plus size of prolog. | 158 void |
| 137 * | 159 VMS__free(void *ptrToFree) |
| 138 * The difference to the regular malloc is, that all the allocated chunks are | 160 { |
| 139 * aligned and padded to the size of a CACHE_LINE. Thus creating a new chunk | 161 MallocPrologAllocated chunk = (MallocPrologAllocated*)ptrToFree - 1; |
| 140 * before the aligned chunk. | 162 if(chunk->procrID == _VMSMasterEnv->currentMasterProcrID) |
| 141 */ | |
| 142 void *VMS__malloc_aligned( size_t sizeRequested ) | |
| 143 { MallocProlog *foundElem = NULL, *currElem, *newElem; | |
| 144 ssize_t amountExtra, sizeConsumed,sizeOfFound,prevAmount; | |
| 145 uint32 foundElemIsTopOfHeap; | |
| 146 | |
| 147 //============================= MEASUREMENT STUFF ======================== | |
| 148 #ifdef MEAS__TIME_MALLOC | |
| 149 uint32 startStamp, endStamp; | |
| 150 saveLowTimeStampCountInto( startStamp ); | |
| 151 #endif | |
| 152 //======================================================================== | |
| 153 | |
| 154 //step up the size to be multiple of the cache line size | |
| 155 sizeRequested = (sizeRequested + CACHE_LINE) & ~(CACHE_LINE-1); | |
| 156 currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList; | |
| 157 | |
| 158 while( currElem != NULL ) | |
| 159 { //check if size of currElem is big enough | |
| 160 sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem); | |
| 161 amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog); | |
| 162 if( amountExtra > 0 ) | |
| 163 { | |
| 164 //look if the found element is already aligned | |
| 165 if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE-1)) == 0){ | |
| 166 //found it, get out of loop | |
| 167 foundElem = currElem; | |
| 168 break; | |
| 169 }else{ | |
| 170 //find first aligned address and check if it's still big enough | |
| 171 //check also if the space before the aligned address is big enough | |
| 172 //for a new element | |
| 173 void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE) & ~((uintptr_t)(CACHE_LINE-1))); | |
| 174 prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem; | |
| 175 sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog); | |
| 176 amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog); | |
| 177 if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){ | |
| 178 //found suitable element | |
| 179 //create new previous element and exit loop | |
| 180 MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1; | |
| 181 | |
| 182 //insert new element into free list | |
| 183 if(currElem->nextChunkInFreeList != NULL) | |
| 184 currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem; | |
| 185 newAlignedElem->prevChunkInFreeList = currElem; | |
| 186 newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList; | |
| 187 currElem->nextChunkInFreeList = newAlignedElem; | |
| 188 | |
| 189 //set higherInMem and lowerInMem | |
| 190 newAlignedElem->nextHigherInMem = currElem->nextHigherInMem; | |
| 191 foundElemIsTopOfHeap = currElem->nextHigherInMem == | |
| 192 _VMSMasterEnv->freeListHead->nextHigherInMem; | |
| 193 if(!foundElemIsTopOfHeap) | |
| 194 currElem->nextHigherInMem->nextLowerInMem = newAlignedElem; | |
| 195 currElem->nextHigherInMem = newAlignedElem; | |
| 196 newAlignedElem->nextLowerInMem = currElem; | |
| 197 | |
| 198 //Found new element leaving loop | |
| 199 foundElem = newAlignedElem; | |
| 200 break; | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 } | |
| 205 currElem = currElem->nextChunkInFreeList; | |
| 206 } | |
| 207 | |
| 208 if( foundElem == NULL ) | |
| 209 { ERROR("\nmalloc failed\n") | |
| 210 return (void *)NULL; //indicates malloc failed | |
| 211 } | |
| 212 //Using a kludge to identify the element that is the top chunk in the | |
| 213 // heap -- saving top-of-heap addr in head's nextHigherInMem -- and | |
| 214 // save addr of start of heap in head's nextLowerInMem | |
| 215 //Will handle top of Heap specially | |
| 216 foundElemIsTopOfHeap = foundElem->nextHigherInMem == | |
| 217 _VMSMasterEnv->freeListHead->nextHigherInMem; | |
| 218 | |
| 219 //before shave off and try to insert new elem, remove found elem | |
| 220 //note, foundElem will never be the head, so always has valid prevChunk | |
| 221 foundElem->prevChunkInFreeList->nextChunkInFreeList = | |
| 222 foundElem->nextChunkInFreeList; | |
| 223 if( foundElem->nextChunkInFreeList != NULL ) | |
| 224 { foundElem->nextChunkInFreeList->prevChunkInFreeList = | |
| 225 foundElem->prevChunkInFreeList; | |
| 226 } | |
| 227 foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated | |
| 228 | |
| 229 //if enough, turn extra into new elem & insert it | |
| 230 if( amountExtra > 64 ) | |
| 231 { //make new elem by adding to addr of curr elem then casting | |
| 232 sizeConsumed = sizeof(MallocProlog) + sizeRequested; | |
| 233 newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed ); | |
| 234 newElem->nextHigherInMem = foundElem->nextHigherInMem; | |
| 235 newElem->nextLowerInMem = foundElem; | |
| 236 foundElem->nextHigherInMem = newElem; | |
| 237 | |
| 238 if( ! foundElemIsTopOfHeap ) | |
| 239 { //there is no next higher for top of heap, so can't write to it | |
| 240 newElem->nextHigherInMem->nextLowerInMem = newElem; | |
| 241 } | |
| 242 add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead ); | |
| 243 } | |
| 244 else | |
| 245 { | 163 { |
| 246 sizeConsumed = sizeOfFound; | 164 VMS__free_on_core(ptrToFree, _VMSMasterEnv->currentMasterProcrID); |
| 247 } | 165 } |
| 248 _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed; | 166 else |
| 249 | 167 { |
| 250 //============================= MEASUREMENT STUFF ======================== | 168 //Request from other Core |
| 251 #ifdef MEAS__TIME_MALLOC | 169 } |
| 252 saveLowTimeStampCountInto( endStamp ); | 170 } |
| 253 addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist ); | 171 |
| 254 #endif | 172 /* |
| 255 //======================================================================== | 173 * This free is called for the plugins. It decides whether the allocation of |
| 256 | 174 * chunk was done on the same core. If it was it calls VMS__free_on_core |
| 257 //skip over the prolog by adding its size to the pointer return | 175 * otherwise it sends a message to the responsible core. |
| 258 return (void*)((uintptr_t)foundElem + sizeof(MallocProlog)); | 176 */ |
| 259 } | 177 void |
| 260 | 178 VMS__free_in_lib(void *ptrToFree, VirtProcr *VProc) |
| 179 { | |
| 180 MallocPrologAllocated chunk = (MallocPrologAllocated*)ptrToFree - 1; | |
| 181 if(chunk->procrID == VProc->coreAnimatedBy) | |
| 182 { | |
| 183 VMS__free_on_core(ptrToFree, VProc->coreAnimatedBy); | |
| 184 } | |
| 185 else | |
| 186 { | |
| 187 //Request from other Core | |
| 188 } | |
| 189 } | |
| 261 | 190 |
| 262 /*This is sequential code -- only to be called from the Master | 191 /*This is sequential code -- only to be called from the Master |
| 263 * When free, subtract the size of prolog from pointer, then cast it to a | 192 * When free, subtract the size of prolog from pointer, then cast it to a |
| 264 * MallocProlog. Then check the nextLower and nextHigher chunks to see if | 193 * MallocProlog. Then check the nextLower and nextHigher chunks to see if |
| 265 * one or both are also free, and coalesce if so, and if neither free, then | 194 * one or both are also free, and coalesce if so, and if neither free, then |
| 266 * add this one to free-list. | 195 * add this one to free-list. |
| 267 */ | 196 */ |
| 268 void | 197 void |
| 269 VMS__free( void *ptrToFree ) | 198 VMS__free_on_core( void *ptrToFree, int procrID) |
| 270 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; | 199 { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem; |
| 271 size_t sizeOfElem; | 200 size_t sizeOfElem; |
| 272 uint32 lowerExistsAndIsFree, higherExistsAndIsFree; | 201 uint32 lowerExistsAndIsFree, higherExistsAndIsFree; |
| 273 | 202 |
| 274 //============================= MEASUREMENT STUFF ======================== | 203 //============================= MEASUREMENT STUFF ======================== |
| 441 /*Designed to be called from the main thread outside of VMS, during init | 370 /*Designed to be called from the main thread outside of VMS, during init |
| 442 */ | 371 */ |
| 443 MallocProlog * | 372 MallocProlog * |
| 444 VMS_ext__create_free_list() | 373 VMS_ext__create_free_list() |
| 445 { MallocProlog *freeListHead, *firstChunk; | 374 { MallocProlog *freeListHead, *firstChunk; |
| 446 | 375 |
| 447 //Note, this is running in the main thread -- all increases in malloc | 376 //Note, this is running in the main thread -- all increases in malloc |
| 448 // mem and all frees of it must be done in this thread, with the | 377 // mem and all frees of it must be done in this thread, with the |
| 449 // thread's original stack available | 378 // thread's original stack available |
| 450 freeListHead = malloc( sizeof(MallocProlog) ); | 379 freeListHead = malloc( sizeof(MallocProlog) ); |
| 451 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); | 380 firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE ); |
