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 );