changeset 101:ca154ebe2b6c malloc2

Basic malloc without small chunks
author Merten Sach <msach@mailbox.tu-berlin.de>
date Tue, 02 Aug 2011 15:44:28 +0200
parents 5ce4b9beeadb
children def70e32cf2c
files VMS.c VMS.h vmalloc.c vmalloc.h
diffstat 4 files changed, 242 insertions(+), 373 deletions(-) [+]
line diff
     1.1 --- a/VMS.c	Tue Jul 26 16:14:30 2011 +0200
     1.2 +++ b/VMS.c	Tue Aug 02 15:44:28 2011 +0200
     1.3 @@ -105,7 +105,7 @@
     1.4          //Very first thing put into the master env is the free-list, seeded
     1.5          // with a massive initial chunk of memory.
     1.6          //After this, all other mallocs are VMS__malloc.
     1.7 -   _VMSMasterEnv->freeListHead        = VMS_ext__create_free_list();
     1.8 +   _VMSMasterEnv->freeLists        = VMS_ext__create_free_list();
     1.9  
    1.10  
    1.11     //============================= MEASUREMENT STUFF ========================
    1.12 @@ -751,7 +751,7 @@
    1.13     //========================================================================
    1.14  */
    1.15        //These are the only two that use system free 
    1.16 -   VMS_ext__free_free_list( _VMSMasterEnv->freeListHead );
    1.17 +   VMS_ext__free_free_list( _VMSMasterEnv->freeLists );
    1.18     free( (void *)_VMSMasterEnv );
    1.19   }
    1.20  
     2.1 --- a/VMS.h	Tue Jul 26 16:14:30 2011 +0200
     2.2 +++ b/VMS.h	Tue Aug 02 15:44:28 2011 +0200
     2.3 @@ -224,7 +224,7 @@
     2.4  
     2.5     void            *semanticEnv;
     2.6     void            *OSEventStruc;   //for future, when add I/O to BLIS
     2.7 -   MallocProlog    *freeListHead;
     2.8 +   MallocArrays    *freeLists;
     2.9     int32            amtOfOutstandingMem; //total currently allocated
    2.10  
    2.11     void            *coreLoopReturnPt;//addr to jump to to re-enter coreLoop
     3.1 --- a/vmalloc.c	Tue Jul 26 16:14:30 2011 +0200
     3.2 +++ b/vmalloc.c	Tue Aug 02 15:44:28 2011 +0200
     3.3 @@ -11,46 +11,188 @@
     3.4  #include <inttypes.h>
     3.5  #include <stdlib.h>
     3.6  #include <stdio.h>
     3.7 +#include <string.h>
     3.8 +#include <math.h>
     3.9  
    3.10  #include "VMS.h"
    3.11  #include "Histogram/Histogram.h"
    3.12  
    3.13 -/*Helper function
    3.14 - *Insert a newly generated free chunk into the first spot on the free list.
    3.15 - * The chunk is cast as a MallocProlog, so the various pointers in it are
    3.16 - * accessed with C's help -- and the size of the prolog is easily added to
    3.17 - * the pointer when a chunk is returned to the app -- so C handles changes
    3.18 - * in pointer sizes among machines.
    3.19 - *
    3.20 - *The list head is a normal MallocProlog struct -- identified by its
    3.21 - * prevChunkInFreeList being NULL -- the only one.
    3.22 - *
    3.23 - *The end of the list is identified by next chunk being NULL, as usual.
    3.24 +/*
    3.25 + * This calculates the container which fits the given size.
    3.26   */
    3.27 -void inline
    3.28 -add_chunk_to_free_list( MallocProlog *chunk, MallocProlog *listHead )
    3.29 - { 
    3.30 -   chunk->nextChunkInFreeList     = listHead->nextChunkInFreeList;
    3.31 -   if( chunk->nextChunkInFreeList != NULL ) //if not last in free list
    3.32 -      chunk->nextChunkInFreeList->prevChunkInFreeList = chunk;
    3.33 -   chunk->prevChunkInFreeList     = listHead;
    3.34 -   listHead->nextChunkInFreeList  = chunk;
    3.35 +inline
    3.36 +uint32 getContainer(size_t size)
    3.37 +{
    3.38 +    return floor((log10(size)-LOG128)/LOG54);
    3.39 +}
    3.40 +
    3.41 +/*
    3.42 + * This calculates the size of a given container
    3.43 + */
    3.44 +inline
    3.45 +size_t getContainerSize(uint32 idx)
    3.46 +{
    3.47 +    return pow(CHUNK_INCREASE_RATE,idx)*LOWER_BOUND;
    3.48 +}
    3.49 +
    3.50 +/*
    3.51 + * Removes the first chunk of a freeList
    3.52 + * The chunk is removed but not set as free. There is no check if
    3.53 + * the free list is empty, so make sure this is not the case.
    3.54 + */
    3.55 +inline
    3.56 +MallocProlog *removeChunk(MallocProlog** container)
    3.57 +{
    3.58 +    MallocProlog *removedChunk = *container;
    3.59 +    *container = removedChunk->nextChunkInFreeList;
    3.60 +    
    3.61 +    if(removedChunk->nextChunkInFreeList)
    3.62 +        removedChunk->nextChunkInFreeList->prevChunkInFreeList = 
    3.63 +                (MallocProlog*)container;
    3.64 +    
    3.65 +    return removedChunk;
    3.66 +}
    3.67 +
    3.68 +/*
    3.69 + * Removes a chunk from a free list.
    3.70 + */
    3.71 +inline
    3.72 +MallocProlog *extractChunk(MallocProlog* chunk)
    3.73 +{
    3.74 +    
    3.75 +}
    3.76 +
    3.77 +/*
    3.78 + * Merges two chunks.
    3.79 + * Chunk A has to be before chunk B in memory.
    3.80 + */
    3.81 +inline
    3.82 +MallocProlog *mergeChunks(MallocProlog* chunkA, MallocProlog* chunkB)
    3.83 +{
    3.84 +    
    3.85 +}
    3.86 +/*
    3.87 + * Inserts a chunk into a free list.
    3.88 + */
    3.89 +inline
    3.90 +void insertChunk(MallocProlog* chunk, MallocProlog** container)
    3.91 +{
    3.92 +    chunk->nextChunkInFreeList = *container;
    3.93 +    chunk->prevChunkInFreeList = (MallocProlog*)container;
    3.94 +    if(*container)
    3.95 +        (*container)->prevChunkInFreeList = chunk;
    3.96 +    *container = chunk;
    3.97 +}
    3.98 +
    3.99 +/*
   3.100 + * Divides the chunk that a new chunk of newSize is created.
   3.101 + * There is no size check, so make sure the size value is valid.
   3.102 + */
   3.103 +inline
   3.104 +MallocProlog *divideChunk(MallocProlog* chunk, size_t newSize)
   3.105 +{
   3.106 +    MallocProlog* newChunk = (MallocProlog*)((uintptr_t)chunk->nextHigherInMem -
   3.107 +            newSize - sizeof(MallocProlog));
   3.108 +    
   3.109 +    newChunk->nextLowerInMem  = chunk;
   3.110 +    newChunk->nextHigherInMem = chunk->nextHigherInMem;
   3.111 +    
   3.112 +    chunk->nextHigherInMem = newChunk;
   3.113 +    chunk->nextHigherInMem->nextLowerInMem = newChunk;
   3.114 +    
   3.115 +    return newChunk;
   3.116 +}
   3.117 +
   3.118 +inline
   3.119 +size_t getChunkSize(MallocProlog* chunk)
   3.120 +{
   3.121 +    return (uintptr_t)chunk->nextHigherInMem -
   3.122 +            (uintptr_t)chunk - sizeof(MallocProlog);
   3.123 +}
   3.124 +
   3.125 +/*
   3.126 + * This is sequential code, meant to only be called from the Master, not from
   3.127 + * any slave VPs.
   3.128 + */
   3.129 +void *VMS__malloc( size_t sizeRequested )
   3.130 + {     
   3.131 +   //============================= MEASUREMENT STUFF ========================
   3.132 +   #ifdef MEAS__TIME_MALLOC
   3.133 +   int32 startStamp, endStamp;
   3.134 +   saveLowTimeStampCountInto( startStamp );
   3.135 +   #endif
   3.136 +   //========================================================================
   3.137 +   
   3.138 +   MallocArrays* freeList = _VMSMasterEnv->freeLists;
   3.139 +   
   3.140 +   //Return a small chunk if the requested size is smaller than 128B
   3.141 +   //TODO: for now set size to 129B
   3.142 +   if(sizeRequested < 128)
   3.143 +       sizeRequested = 129;
   3.144 +           
   3.145 +   //Calculate the expected container. Start one higher to have a Chunk that's
   3.146 +   //always big enough.
   3.147 +   uint32 targetContainerIdx = getContainer(sizeRequested);
   3.148 +   uint32 containerIdx = targetContainerIdx + 1;
   3.149 +   
   3.150 +   MallocProlog* foundChunk;
   3.151 +   if(freeList->bigChunks[containerIdx] == NULL)
   3.152 +   {
   3.153 +       while(freeList->bigChunks[containerIdx] == NULL)
   3.154 +       {
   3.155 +           containerIdx++;
   3.156 +           if(containerIdx > freeList->containerCount)
   3.157 +           {
   3.158 +               printf("VMS malloc failed: low memory");
   3.159 +               exit(1);
   3.160 +           }
   3.161 +       }
   3.162 +       
   3.163 +       foundChunk = removeChunk(&freeList->bigChunks[containerIdx]);
   3.164 +       //Found bigger Element, so we have to divide until it fits the
   3.165 +       //requested size
   3.166 +       containerIdx--;       
   3.167 +       size_t containerSize = getContainerSize(containerIdx);
   3.168 +       size_t chunkSize     = getChunkSize(foundChunk);
   3.169 +       
   3.170 +       while(containerIdx > targetContainerIdx)
   3.171 +       {
   3.172 +           if(chunkSize > containerSize + sizeRequested + sizeof(MallocProlog))
   3.173 +           {
   3.174 +               MallocProlog *newChunk = divideChunk(foundChunk,containerSize);
   3.175 +               insertChunk(newChunk,&freeList->bigChunks[containerIdx]);
   3.176 +               chunkSize = getChunkSize(foundChunk);
   3.177 +           }
   3.178 +           containerIdx--;
   3.179 +           containerSize /= CHUNK_INCREASE_RATE;
   3.180 +       }
   3.181 +   }
   3.182 +   else
   3.183 +   {
   3.184 +        foundChunk = removeChunk(&freeList->bigChunks[containerIdx]); 
   3.185 +   }
   3.186 +   
   3.187 +   //Mark as allocated
   3.188 +   foundChunk->prevChunkInFreeList = NULL;      
   3.189 +   
   3.190 +   //============================= MEASUREMENT STUFF ========================
   3.191 +   #ifdef MEAS__TIME_MALLOC
   3.192 +   saveLowTimeStampCountInto( endStamp );
   3.193 +   addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
   3.194 +   #endif
   3.195 +   //========================================================================
   3.196 +
   3.197 +   //skip over the prolog by adding its size to the pointer return
   3.198 +   return (void*)((uintptr_t)foundChunk + sizeof(MallocProlog));
   3.199   }
   3.200  
   3.201 -
   3.202 -/*This is sequential code, meant to only be called from the Master, not from
   3.203 +/*
   3.204 + * This is sequential code, meant to only be called from the Master, not from
   3.205   * any slave VPs.
   3.206 - *Search down list, checking size by the nextHigherInMem pointer, to find
   3.207 - * first chunk bigger than size needed.
   3.208 - *Shave off the extra and make it into a new free-list element, hook it in
   3.209 - * then return the address of the found element plus size of prolog.
   3.210 - *
   3.211 - *Will find a
   3.212   */
   3.213 -void *VMS__malloc( size_t sizeRequested )
   3.214 - { MallocProlog *foundElem = NULL, *currElem, *newElem;
   3.215 -   ssize_t        amountExtra, sizeConsumed,sizeOfFound;
   3.216 -   uint32        foundElemIsTopOfHeap;
   3.217 +void
   3.218 +VMS__free( void *ptrToFree )
   3.219 + {
   3.220  
   3.221     //============================= MEASUREMENT STUFF ========================
   3.222     #ifdef MEAS__TIME_MALLOC
   3.223 @@ -59,312 +201,17 @@
   3.224     #endif
   3.225     //========================================================================
   3.226     
   3.227 -      //step up the size to be aligned at 16-byte boundary, prob better ways
   3.228 -   sizeRequested = (sizeRequested + 16) & ~15;
   3.229 -   currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
   3.230 -
   3.231 -   while( currElem != NULL )
   3.232 -    {    //check if size of currElem is big enough
   3.233 -      sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
   3.234 -      amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
   3.235 -      if( amountExtra > 0 )
   3.236 -       {    //found it, get out of loop
   3.237 -         foundElem = currElem;
   3.238 -         currElem = NULL;
   3.239 +   MallocArrays* freeList = _VMSMasterEnv->freeLists;
   3.240 +   MallocProlog *chunkToFree = (MallocProlog*)ptrToFree - 1;
   3.241 +   
   3.242 +   //Check for free neighbors
   3.243 +   if(chunkToFree->nextLowerInMem)
   3.244 +   {
   3.245 +       if(chunkToFree->nextLowerInMem->prevChunkInFreeList != NULL)
   3.246 +       {//Chunk is not allocated
   3.247 +           mergeChunks()
   3.248         }
   3.249 -      else
   3.250 -         currElem = currElem->nextChunkInFreeList;
   3.251 -    }
   3.252 -   
   3.253 -   if( foundElem == NULL )
   3.254 -    { ERROR("\nmalloc failed\n")
   3.255 -      return (void *)NULL;  //indicates malloc failed
   3.256 -    }
   3.257 -      //Using a kludge to identify the element that is the top chunk in the
   3.258 -      // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
   3.259 -      // save addr of start of heap in head's nextLowerInMem
   3.260 -      //Will handle top of Heap specially
   3.261 -   foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
   3.262 -                          _VMSMasterEnv->freeListHead->nextHigherInMem;
   3.263 -   
   3.264 -      //before shave off and try to insert new elem, remove found elem
   3.265 -      //note, foundElem will never be the head, so always has valid prevChunk
   3.266 -   foundElem->prevChunkInFreeList->nextChunkInFreeList =
   3.267 -                                              foundElem->nextChunkInFreeList;
   3.268 -   if( foundElem->nextChunkInFreeList != NULL )
   3.269 -    { foundElem->nextChunkInFreeList->prevChunkInFreeList =
   3.270 -                                              foundElem->prevChunkInFreeList;
   3.271 -    }
   3.272 -   foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
   3.273 -   
   3.274 -      //if enough, turn extra into new elem & insert it
   3.275 -   if( amountExtra > 64 )
   3.276 -    {   //make new elem by adding to addr of curr elem then casting
   3.277 -        sizeConsumed = sizeof(MallocProlog) + sizeRequested; 
   3.278 -        newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed );
   3.279 -        newElem->nextLowerInMem    = foundElem; //This is evil (but why?) 
   3.280 -        newElem->nextHigherInMem   = foundElem->nextHigherInMem; //This is evil (but why?)
   3.281 -        foundElem->nextHigherInMem = newElem;
   3.282 -        if( ! foundElemIsTopOfHeap )
   3.283 -        {  //there is no next higher for top of heap, so can't write to it
   3.284 -           newElem->nextHigherInMem->nextLowerInMem = newElem;
   3.285 -        }
   3.286 -        add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
   3.287 -    }
   3.288 -   else
   3.289 -    {
   3.290 -      sizeConsumed = sizeOfFound;
   3.291 -    }
   3.292 -  _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
   3.293 -
   3.294 -   //============================= MEASUREMENT STUFF ========================
   3.295 -   #ifdef MEAS__TIME_MALLOC
   3.296 -   saveLowTimeStampCountInto( endStamp );
   3.297 -   addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
   3.298 -   #endif
   3.299 -   //========================================================================
   3.300 -
   3.301 -      //skip over the prolog by adding its size to the pointer return
   3.302 -   return (void*)((uintptr_t)foundElem + sizeof(MallocProlog));
   3.303 - }
   3.304 -
   3.305 -/*This is sequential code, meant to only be called from the Master, not from
   3.306 - * any slave VPs.
   3.307 - *Search down list, checking size by the nextHigherInMem pointer, to find
   3.308 - * first chunk bigger than size needed.
   3.309 - *Shave off the extra and make it into a new free-list element, hook it in
   3.310 - * then return the address of the found element plus size of prolog.
   3.311 - *
   3.312 - * The difference to the regular malloc is, that all the allocated chunks are
   3.313 - * aligned and padded to the size of a CACHE_LINE. Thus creating a new chunk
   3.314 - * before the aligned chunk.
   3.315 - */
   3.316 -void *VMS__malloc_aligned( size_t sizeRequested )
   3.317 - { MallocProlog *foundElem = NULL, *currElem, *newElem;
   3.318 -   ssize_t        amountExtra, sizeConsumed,sizeOfFound,prevAmount;
   3.319 -   uint32        foundElemIsTopOfHeap;
   3.320 -
   3.321 -   //============================= MEASUREMENT STUFF ========================
   3.322 -   #ifdef MEAS__TIME_MALLOC
   3.323 -   uint32 startStamp, endStamp;
   3.324 -   saveLowTimeStampCountInto( startStamp );
   3.325 -   #endif
   3.326 -   //========================================================================
   3.327 -   
   3.328 -      //step up the size to be multiple of the cache line size
   3.329 -   sizeRequested = (sizeRequested + CACHE_LINE) & ~(CACHE_LINE-1);
   3.330 -   currElem = (_VMSMasterEnv->freeListHead)->nextChunkInFreeList;
   3.331 -
   3.332 -   while( currElem != NULL )
   3.333 -    {    //check if size of currElem is big enough
   3.334 -      sizeOfFound=(size_t)((uintptr_t)currElem->nextHigherInMem -(uintptr_t)currElem);
   3.335 -      amountExtra = sizeOfFound - sizeRequested - sizeof(MallocProlog);
   3.336 -      if( amountExtra > 0 )
   3.337 -       {    
   3.338 -         //look if the found element is already aligned
   3.339 -         if((((uintptr_t)currElem+sizeof(MallocProlog)) & (uintptr_t)(CACHE_LINE-1)) == 0){
   3.340 -             //found it, get out of loop
   3.341 -             foundElem = currElem;
   3.342 -             break;
   3.343 -         }else{
   3.344 -             //find first aligned address and check if it's still big enough
   3.345 -             //check also if the space before the aligned address is big enough
   3.346 -             //for a new element
   3.347 -             void *firstAlignedAddr = (void*)(((uintptr_t)currElem + 2*CACHE_LINE) & ~((uintptr_t)(CACHE_LINE-1)));
   3.348 -             prevAmount = (uintptr_t)firstAlignedAddr - (uintptr_t)currElem;
   3.349 -             sizeOfFound=(uintptr_t)currElem->nextHigherInMem -(uintptr_t)firstAlignedAddr + sizeof(MallocProlog);
   3.350 -             amountExtra= sizeOfFound - sizeRequested - sizeof(MallocProlog);
   3.351 -             if(prevAmount > 2*sizeof(MallocProlog) && amountExtra > 0 ){
   3.352 -                 //found suitable element
   3.353 -                 //create new previous element and exit loop
   3.354 -                 MallocProlog *newAlignedElem = (MallocProlog*)firstAlignedAddr - 1;
   3.355 -                 
   3.356 -                 //insert new element into free list
   3.357 -                 if(currElem->nextChunkInFreeList != NULL)
   3.358 -                     currElem->nextChunkInFreeList->prevChunkInFreeList = newAlignedElem;                     
   3.359 -                 newAlignedElem->prevChunkInFreeList = currElem;
   3.360 -                 newAlignedElem->nextChunkInFreeList = currElem->nextChunkInFreeList;
   3.361 -                 currElem->nextChunkInFreeList = newAlignedElem;
   3.362 -                 
   3.363 -                 //set higherInMem and lowerInMem
   3.364 -                 newAlignedElem->nextHigherInMem = currElem->nextHigherInMem;
   3.365 -                 foundElemIsTopOfHeap = currElem->nextHigherInMem ==
   3.366 -                          _VMSMasterEnv->freeListHead->nextHigherInMem;
   3.367 -                 if(!foundElemIsTopOfHeap)
   3.368 -                     currElem->nextHigherInMem->nextLowerInMem = newAlignedElem;
   3.369 -                 currElem->nextHigherInMem = newAlignedElem;
   3.370 -                 newAlignedElem->nextLowerInMem = currElem;
   3.371 -                 
   3.372 -                 //Found new element leaving loop
   3.373 -                 foundElem = newAlignedElem;
   3.374 -                 break;
   3.375 -             }
   3.376 -         }
   3.377 -         
   3.378 -       }
   3.379 -       currElem = currElem->nextChunkInFreeList;
   3.380 -    }
   3.381 -
   3.382 -   if( foundElem == NULL )
   3.383 -    { ERROR("\nmalloc failed\n")
   3.384 -      return (void *)NULL;  //indicates malloc failed
   3.385 -    }
   3.386 -      //Using a kludge to identify the element that is the top chunk in the
   3.387 -      // heap -- saving top-of-heap addr in head's nextHigherInMem -- and
   3.388 -      // save addr of start of heap in head's nextLowerInMem
   3.389 -      //Will handle top of Heap specially
   3.390 -   foundElemIsTopOfHeap = foundElem->nextHigherInMem ==
   3.391 -                          _VMSMasterEnv->freeListHead->nextHigherInMem;
   3.392 -
   3.393 -      //before shave off and try to insert new elem, remove found elem
   3.394 -      //note, foundElem will never be the head, so always has valid prevChunk
   3.395 -   foundElem->prevChunkInFreeList->nextChunkInFreeList =
   3.396 -                                              foundElem->nextChunkInFreeList;
   3.397 -   if( foundElem->nextChunkInFreeList != NULL )
   3.398 -    { foundElem->nextChunkInFreeList->prevChunkInFreeList =
   3.399 -                                              foundElem->prevChunkInFreeList;
   3.400 -    }
   3.401 -   foundElem->prevChunkInFreeList = NULL;//indicates elem currently allocated
   3.402 -   
   3.403 -      //if enough, turn extra into new elem & insert it
   3.404 -   if( amountExtra > 64 )
   3.405 -    {    //make new elem by adding to addr of curr elem then casting
   3.406 -      sizeConsumed = sizeof(MallocProlog) + sizeRequested;
   3.407 -      newElem = (MallocProlog *)( (uintptr_t)foundElem + sizeConsumed );
   3.408 -      newElem->nextHigherInMem   = foundElem->nextHigherInMem;
   3.409 -      newElem->nextLowerInMem    = foundElem;
   3.410 -      foundElem->nextHigherInMem = newElem;
   3.411 -      
   3.412 -      if( ! foundElemIsTopOfHeap )
   3.413 -       {    //there is no next higher for top of heap, so can't write to it
   3.414 -         newElem->nextHigherInMem->nextLowerInMem = newElem;
   3.415 -       }
   3.416 -      add_chunk_to_free_list( newElem, _VMSMasterEnv->freeListHead );
   3.417 -    }
   3.418 -   else
   3.419 -    {
   3.420 -      sizeConsumed = sizeOfFound;
   3.421 -    }
   3.422 -  _VMSMasterEnv->amtOfOutstandingMem += sizeConsumed;
   3.423 -
   3.424 -   //============================= MEASUREMENT STUFF ========================
   3.425 -   #ifdef MEAS__TIME_MALLOC
   3.426 -   saveLowTimeStampCountInto( endStamp );
   3.427 -   addIntervalToHist( startStamp, endStamp, _VMSMasterEnv->mallocTimeHist );
   3.428 -   #endif
   3.429 -   //========================================================================
   3.430 -
   3.431 -      //skip over the prolog by adding its size to the pointer return
   3.432 -   return (void*)((uintptr_t)foundElem + sizeof(MallocProlog));
   3.433 - }
   3.434 -
   3.435 -
   3.436 -/*This is sequential code -- only to be called from the Master
   3.437 - * When free, subtract the size of prolog from pointer, then cast it to a
   3.438 - * MallocProlog.  Then check the nextLower and nextHigher chunks to see if
   3.439 - * one or both are also free, and coalesce if so, and if neither free, then
   3.440 - * add this one to free-list.
   3.441 - */
   3.442 -void
   3.443 -VMS__free( void *ptrToFree )
   3.444 - { MallocProlog *elemToFree, *nextLowerElem, *nextHigherElem;
   3.445 -   size_t         sizeOfElem;
   3.446 -   uint32         lowerExistsAndIsFree, higherExistsAndIsFree;
   3.447 -
   3.448 -   //============================= MEASUREMENT STUFF ========================
   3.449 -   #ifdef MEAS__TIME_MALLOC
   3.450 -   int32 startStamp, endStamp;
   3.451 -   saveLowTimeStampCountInto( startStamp );
   3.452 -   #endif
   3.453 -   //========================================================================
   3.454 -
   3.455 -   if( ptrToFree < (void*)_VMSMasterEnv->freeListHead->nextLowerInMem ||
   3.456 -       ptrToFree > (void*)_VMSMasterEnv->freeListHead->nextHigherInMem )
   3.457 -    {    //outside the range of data owned by VMS's malloc, so do nothing
   3.458 -      return;
   3.459 -    }
   3.460 -      //subtract size of prolog to get pointer to prolog, then cast
   3.461 -   elemToFree = (MallocProlog *)((uintptr_t)ptrToFree - sizeof(MallocProlog));
   3.462 -   sizeOfElem =(size_t)((uintptr_t)elemToFree->nextHigherInMem-(uintptr_t)elemToFree);
   3.463 -
   3.464 -   if( elemToFree->prevChunkInFreeList != NULL )
   3.465 -    { printf( "error: freeing same element twice!" ); exit(1);
   3.466 -    }
   3.467 -
   3.468 -   _VMSMasterEnv->amtOfOutstandingMem -= sizeOfElem;
   3.469 -
   3.470 -   nextLowerElem  = elemToFree->nextLowerInMem;
   3.471 -   nextHigherElem = elemToFree->nextHigherInMem;
   3.472 -
   3.473 -   if( nextHigherElem == NULL )
   3.474 -      higherExistsAndIsFree = FALSE;
   3.475 -   else //okay exists, now check if in the free-list by checking back ptr
   3.476 -      higherExistsAndIsFree = (nextHigherElem->prevChunkInFreeList != NULL);
   3.477 -    
   3.478 -   if( nextLowerElem == NULL )
   3.479 -      lowerExistsAndIsFree = FALSE;
   3.480 -   else //okay, it exists, now check if it's free
   3.481 -      lowerExistsAndIsFree = (nextLowerElem->prevChunkInFreeList != NULL);
   3.482 -    
   3.483 -
   3.484 -      //now, know what exists and what's free
   3.485 -   if( lowerExistsAndIsFree )
   3.486 -    { if( higherExistsAndIsFree )
   3.487 -       {    //both exist and are free, so coalesce all three
   3.488 -            //First, remove higher from free-list
   3.489 -         nextHigherElem->prevChunkInFreeList->nextChunkInFreeList =
   3.490 -                                         nextHigherElem->nextChunkInFreeList;
   3.491 -         if( nextHigherElem->nextChunkInFreeList != NULL ) //end-of-list?
   3.492 -            nextHigherElem->nextChunkInFreeList->prevChunkInFreeList =
   3.493 -                                         nextHigherElem->prevChunkInFreeList;
   3.494 -            //Now, fix-up sequence-in-mem list -- by side-effect, this also
   3.495 -            // changes size of the lower elem, which is still in free-list
   3.496 -         nextLowerElem->nextHigherInMem = nextHigherElem->nextHigherInMem;
   3.497 -         if( nextHigherElem->nextHigherInMem !=
   3.498 -             _VMSMasterEnv->freeListHead->nextHigherInMem )
   3.499 -            nextHigherElem->nextHigherInMem->nextLowerInMem = nextLowerElem;
   3.500 -            //notice didn't do anything to elemToFree -- it simply is no
   3.501 -            // longer reachable from any of the lists.  Wonder if could be a
   3.502 -            // security leak because left valid addresses in it,
   3.503 -            // but don't care for now.
   3.504 -       }
   3.505 -      else
   3.506 -       {    //lower is the only of the two that exists and is free,
   3.507 -            //In this case, no adjustment to free-list, just change mem-list.
   3.508 -            // By side-effect, changes size of the lower elem
   3.509 -         nextLowerElem->nextHigherInMem = elemToFree->nextHigherInMem;
   3.510 -         if( elemToFree->nextHigherInMem !=
   3.511 -             _VMSMasterEnv->freeListHead->nextHigherInMem )
   3.512 -            elemToFree->nextHigherInMem->nextLowerInMem = nextLowerElem;
   3.513 -       }
   3.514 -    }
   3.515 -   else
   3.516 -    {    //lower either doesn't exist or isn't free, so check higher
   3.517 -      if( higherExistsAndIsFree )
   3.518 -       {    //higher exists and is the only of the two free
   3.519 -            //First, in free-list, replace higher elem with the one to free
   3.520 -         elemToFree->nextChunkInFreeList=nextHigherElem->nextChunkInFreeList;
   3.521 -         elemToFree->prevChunkInFreeList=nextHigherElem->prevChunkInFreeList;
   3.522 -         elemToFree->prevChunkInFreeList->nextChunkInFreeList = elemToFree;
   3.523 -         if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
   3.524 -            elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
   3.525 -            //Now chg mem-list. By side-effect, changes size of elemToFree
   3.526 -         elemToFree->nextHigherInMem = nextHigherElem->nextHigherInMem;
   3.527 -         if( elemToFree->nextHigherInMem !=
   3.528 -             _VMSMasterEnv->freeListHead->nextHigherInMem )
   3.529 -            elemToFree->nextHigherInMem->nextLowerInMem = elemToFree;
   3.530 -       }
   3.531 -      else
   3.532 -       {    //neither lower nor higher is availabe to coalesce so add to list
   3.533 -            // this makes prev chunk ptr non-null, which indicates it's free
   3.534 -         elemToFree->nextChunkInFreeList =
   3.535 -                            _VMSMasterEnv->freeListHead->nextChunkInFreeList;
   3.536 -         _VMSMasterEnv->freeListHead->nextChunkInFreeList = elemToFree;
   3.537 -         if( elemToFree->nextChunkInFreeList != NULL ) // end-of-list?
   3.538 -            elemToFree->nextChunkInFreeList->prevChunkInFreeList =elemToFree;
   3.539 -         elemToFree->prevChunkInFreeList = _VMSMasterEnv->freeListHead;
   3.540 -       }
   3.541 -    }
   3.542 +   }
   3.543     //============================= MEASUREMENT STUFF ========================
   3.544     #ifdef MEAS__TIME_MALLOC
   3.545     saveLowTimeStampCountInto( endStamp );
   3.546 @@ -440,43 +287,47 @@
   3.547  
   3.548  /*Designed to be called from the main thread outside of VMS, during init
   3.549   */
   3.550 -MallocProlog *
   3.551 +MallocArrays *
   3.552  VMS_ext__create_free_list()
   3.553 - { MallocProlog *freeListHead, *firstChunk;
   3.554 -
   3.555 -      //Note, this is running in the main thread -- all increases in malloc
   3.556 -      // mem and all frees of it must be done in this thread, with the
   3.557 -      // thread's original stack available
   3.558 -   freeListHead = malloc( sizeof(MallocProlog) );
   3.559 -   firstChunk   = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
   3.560 +{     
   3.561 +   //Initialize containers for small chunks and fill with zeros
   3.562 +   _VMSMasterEnv->freeLists = (MallocArrays*)malloc( sizeof(MallocArrays) );
   3.563 +   MallocArrays *freeLists = _VMSMasterEnv->freeLists;
   3.564 +   
   3.565 +   freeLists->smallChunks = 
   3.566 +           (MallocProlog**)malloc(SMALL_CHUNK_COUNT*sizeof(MallocProlog*));
   3.567 +   memset((void*)freeLists->smallChunks,
   3.568 +           0,SMALL_CHUNK_COUNT*sizeof(MallocProlog*));
   3.569 +   
   3.570 +   //Calculate number of containers for big chunks
   3.571 +   uint32 container = getContainer(MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE)+1;
   3.572 +   
   3.573 +   freeLists->bigChunks = (MallocProlog**)malloc(container*sizeof(MallocProlog*));
   3.574 +   memset((void*)freeLists->bigChunks,0,container*sizeof(MallocProlog*));
   3.575 +   freeLists->containerCount = container;
   3.576 +   
   3.577 +   //Create first element in lastContainer 
   3.578 +   MallocProlog *firstChunk = malloc( MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE );
   3.579     if( firstChunk == NULL ) {printf("malloc error\n"); exit(1);}
   3.580     
   3.581 -   //Touch memory to avoid page faults
   3.582 -   void *ptr,*endPtr; 
   3.583 -   endPtr = (void*)firstChunk+MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE;
   3.584 -   for(ptr = firstChunk; ptr < endPtr; ptr+=PAGE_SIZE)
   3.585 -   {
   3.586 -       *(char*)ptr = 0;
   3.587 -   }
   3.588 -
   3.589 -   freeListHead->prevChunkInFreeList = NULL;
   3.590 -      //Use this addr to free the heap when cleanup
   3.591 -   freeListHead->nextLowerInMem      = firstChunk;
   3.592 -      //to identify top-of-heap elem, compare this addr to elem's next higher
   3.593 -   freeListHead->nextHigherInMem     = (void*)( (uintptr_t)firstChunk +
   3.594 -                                         MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
   3.595 -   freeListHead->nextChunkInFreeList = firstChunk;
   3.596 -
   3.597 -   firstChunk->nextChunkInFreeList   = NULL;
   3.598 -   firstChunk->prevChunkInFreeList   = freeListHead;
   3.599 -      //next Higher has to be set to top of chunk, so can calc size in malloc
   3.600 -   firstChunk->nextHigherInMem       = (void*)( (uintptr_t)firstChunk +
   3.601 -                                         MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE);
   3.602 -   firstChunk->nextLowerInMem        = NULL; //identifies as bott of heap
   3.603 +   firstChunk->nextLowerInMem = NULL;
   3.604 +   firstChunk->nextHigherInMem = (MallocProlog*)((uintptr_t)firstChunk +
   3.605 +                        MALLOC_ADDITIONAL_MEM_FROM_OS_SIZE - sizeof(MallocProlog*));
   3.606 +   firstChunk->nextChunkInFreeList = NULL;
   3.607 +   //previous element in the queue is the container
   3.608 +   firstChunk->prevChunkInFreeList = freeLists->bigChunks[container-1];
   3.609     
   3.610 -   _VMSMasterEnv->amtOfOutstandingMem = 0; //none allocated yet
   3.611 -
   3.612 -   return freeListHead;
   3.613 +   freeLists->bigChunks[container-1] = firstChunk;
   3.614 +   
   3.615 +   //Create dummy chunk to mark the top of stack this is of course
   3.616 +   //never freed
   3.617 +   MallocProlog *dummyChunk = firstChunk->nextHigherInMem;
   3.618 +   dummyChunk->nextHigherInMem = dummyChunk+1;
   3.619 +   dummyChunk->nextLowerInMem  = NULL;
   3.620 +   dummyChunk->nextChunkInFreeList = NULL;
   3.621 +   dummyChunk->prevChunkInFreeList = NULL;
   3.622 +   
   3.623 +   return freeLists;
   3.624   }
   3.625  
   3.626  
     4.1 --- a/vmalloc.h	Tue Jul 26 16:14:30 2011 +0200
     4.2 +++ b/vmalloc.h	Tue Aug 02 15:44:28 2011 +0200
     4.3 @@ -14,6 +14,14 @@
     4.4  #include <inttypes.h>
     4.5  #include "VMS_primitive_data_types.h"
     4.6  
     4.7 +#define SMALL_CHUNK_SIZE 32
     4.8 +#define SMALL_CHUNK_COUNT 4
     4.9 +#define LOWER_BOUND 128
    4.10 +#define CHUNK_INCREASE_RATE 1.25
    4.11 +
    4.12 +#define LOG54 0.096910013
    4.13 +#define LOG128 2.10720997
    4.14 +
    4.15  typedef struct _MallocProlog MallocProlog;
    4.16  
    4.17  struct _MallocProlog
    4.18 @@ -24,6 +32,16 @@
    4.19     MallocProlog *nextLowerInMem;
    4.20   };
    4.21  //MallocProlog
    4.22 + 
    4.23 + typedef struct MallocArrays MallocArrays;
    4.24 +
    4.25 + struct MallocArrays
    4.26 + {
    4.27 +     MallocProlog **smallChunks;
    4.28 +     MallocProlog **bigChunks;
    4.29 +     uint32       containerCount;
    4.30 + };
    4.31 + //MallocArrays
    4.32  
    4.33  typedef struct
    4.34   {
    4.35 @@ -52,7 +70,7 @@
    4.36  VMS__free_in_ext( void *ptrToFree );
    4.37  
    4.38  
    4.39 -MallocProlog *
    4.40 +MallocArrays *
    4.41  VMS_ext__create_free_list();
    4.42  
    4.43  void