Commenting is nice
[tpg/acess2.git] / Kernel / heap.c
index 61f7881..5e6ccfe 100644 (file)
 #define        DEBUG_TRACE     0
 
 // === CONSTANTS ===
-#define HEAP_BASE      0xE0800000
-#define HEAP_MAX       0xF0000000      // 120MiB, Plenty
 #define        HEAP_INIT_SIZE  0x8000  // 32 KiB
-#define        BLOCK_SIZE      (sizeof(void*)) // 8 Machine Words
+#define        BLOCK_SIZE      (sizeof(void*))*8       // 8 Machine Words
 #define        COMPACT_HEAP    0       // Use 4 byte header?
 #define        FIRST_FIT       0
 
 #define        MAGIC_USED      0x862B0505      // MAGIC_FOOT ^ MAGIC_FREE
 
 // === PROTOTYPES ===
-void   Heap_Install();
+void   Heap_Install(void);
 void   *Heap_Extend(int Bytes);
 void   *Heap_Merge(tHeapHead *Head);
 void   *malloc(size_t Bytes);
 void   free(void *Ptr);
-void   Heap_Dump();
+void   Heap_Dump(void);
+void   Heap_Stats(void);
 
 // === GLOBALS ===
- int   glHeap;
+tSpinlock      glHeap;
 void   *gHeapStart;
 void   *gHeapEnd;
 
 // === CODE ===
-void Heap_Install()
+void Heap_Install(void)
 {
        gHeapStart      = (void*)MM_KHEAP_BASE;
        gHeapEnd        = (void*)MM_KHEAP_BASE;
@@ -53,18 +52,18 @@ void *Heap_Extend(int Bytes)
        tHeapFoot       *foot;
        
        // Bounds Check
-       if( (Uint)gHeapEnd == MM_KHEAP_MAX )
+       if( (tVAddr)gHeapEnd == MM_KHEAP_MAX )
                return NULL;
        
        // Bounds Check
-       if( (Uint)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
-               Bytes = MM_KHEAP_MAX - (Uint)gHeapEnd;
+       if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
+               Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
                return NULL;
        }
        
        // Heap expands in pages
        for(i=0;i<(Bytes+0xFFF)>>12;i++)
-               MM_Allocate( (Uint)gHeapEnd+(i<<12) );
+               MM_Allocate( (tVAddr)gHeapEnd+(i<<12) );
        
        // Increas heap end
        gHeapEnd += i << 12;
@@ -76,7 +75,6 @@ void *Heap_Extend(int Bytes)
        foot->Head = head;
        foot->Magic = MAGIC_FOOT;
        
-       //Log(" Heap_Extend: head = %p", head);
        return Heap_Merge(head);        // Merge with previous block
 }
 
@@ -97,7 +95,7 @@ void *Heap_Merge(tHeapHead *Head)
        
        // Merge Left (Down)
        foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
-       if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > HEAP_BASE)
+       if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
        && foot->Head->Magic == MAGIC_FREE) {
                foot->Head->Size += Head->Size; // Increase size
                thisFoot->Head = foot->Head;    // Change backlink
@@ -150,11 +148,11 @@ void *malloc(size_t Bytes)
        {
                // Alignment Check
                if( head->Size & (BLOCK_SIZE-1) ) {
+                       RELEASE(&glHeap);       // Release spinlock
                        #if WARNINGS
-                       Warning("Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
+                       Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
                        Heap_Dump();
                        #endif
-                       RELEASE(&glHeap);
                        return NULL;
                }
                
@@ -162,11 +160,11 @@ void *malloc(size_t Bytes)
                if(head->Magic == MAGIC_USED)   continue;
                // Error check
                if(head->Magic != MAGIC_FREE)   {
+                       RELEASE(&glHeap);       // Release spinlock
                        #if WARNINGS
-                       Warning("Magic of heap address %p is invalid (0x%x)", head, head->Magic);
+                       Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic);
                        Heap_Dump();
                        #endif
-                       RELEASE(&glHeap);       // Release spinlock
                        return NULL;
                }
                
@@ -178,9 +176,9 @@ void *malloc(size_t Bytes)
                        head->Magic = MAGIC_USED;
                        RELEASE(&glHeap);       // Release spinlock
                        #if DEBUG_TRACE
-                       LOG("RETURN %p, to %p", best->Data, __builtin_return_address(0));
+                       Log("[Heap   ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size,  __builtin_return_address(0));
                        #endif
-                       return best->Data;
+                       return head->Data;
                }
                
                // Break out of loop
@@ -208,9 +206,10 @@ void *malloc(size_t Bytes)
                }
                // Check size
                if(best->Size == Bytes) {
+                       best->Magic = MAGIC_USED;       // Mark block as used
                        RELEASE(&glHeap);       // Release spinlock
                        #if DEBUG_TRACE
-                       LOG("RETURN %p, to %p", best->Data, __builtin_return_address(0));
+                       Log("[Heap   ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
                        #endif
                        return best->Data;
                }
@@ -231,7 +230,7 @@ void *malloc(size_t Bytes)
        
        RELEASE(&glHeap);       // Release spinlock
        #if DEBUG_TRACE
-       LOG("RETURN %p, to %p", best->Data, __builtin_return_address(0));
+       Log("[Heap   ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
        #endif
        return best->Data;
 }
@@ -246,42 +245,43 @@ void free(void *Ptr)
        tHeapFoot       *foot;
        
        #if DEBUG_TRACE
-       LOG("Ptr = %p", Ptr);
-       LOG("Returns to %p", __builtin_return_address(0));
+       Log_Log("Heap", "free: Ptr = %p", Ptr);
+       Log_Log("Heap", "free: Returns to %p", __builtin_return_address(0));
        #endif
        
        // Alignment Check
        if( (Uint)Ptr & (sizeof(Uint)-1) ) {
-               Warning("free - Passed a non-aligned address (%p)", Ptr);
+               Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
                return;
        }
        
        // Sanity check
        if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
        {
-               Warning("free - Passed a non-heap address (%p)\n", Ptr);
+               Log_Warning("Heap", "free - Passed a non-heap address (%p < %p < %p)\n",
+                       gHeapStart, Ptr, gHeapEnd);
                return;
        }
        
        // Check memory block - Header
        head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
        if(head->Magic == MAGIC_FREE) {
-               Warning("free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
+               Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
                return;
        }
        if(head->Magic != MAGIC_USED) {
-               Warning("free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
+               Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
                return;
        }
        
        // Check memory block - Footer
        foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
        if(foot->Head != head) {
-               Warning("free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
+               Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
                return;
        }
        if(foot->Magic != MAGIC_FOOT) {
-               Warning("free - Footer magic is invalid (%p, %p = 0x%x)\n", head, &foot->Magic, foot->Magic);
+               Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)\n", head, &foot->Magic, foot->Magic);
                return;
        }
        
@@ -347,8 +347,15 @@ void *realloc(void *__ptr, size_t __size)
        if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
        {
                Uint    size = nextHead->Size + head->Size;
+               // Inexact fit, split things up
+               if(size > newSize)
+               {
+                       // TODO
+                       Warning("[Heap   ] TODO: Space efficient realloc when new size is smaller");
+               }
+               
                // Exact fit
-               if(size == newSize)
+               if(size >= newSize)
                {
                        Uint    oldDataSize;
                        // Set 1st (new/lower) header
@@ -362,11 +369,27 @@ void *realloc(void *__ptr, size_t __size)
                        // Clear old header
                        head->Size = 0;
                        head->Magic = 0;
+                       // Copy data
                        memcpy(nextHead->Data, __ptr, oldDataSize);
+                       // Return
+                       return nextHead->Data;
                }
+               // On to the expensive then
        }
        
-       return NULL;
+       // Well, darn
+       nextHead = malloc( __size );
+       nextHead -= 1;
+       
+       memcpy(
+               nextHead->Data,
+               __ptr,
+               head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead)
+               );
+       
+       free(__ptr);
+       
+       return nextHead->Data;
 }
 
 /**
@@ -387,13 +410,14 @@ void *calloc(size_t num, size_t size)
 
 /**
  * \fn int IsHeap(void *Ptr)
- * \brief Checks if an address is a heap address
+ * \brief Checks if an address is a heap pointer
  */
 int IsHeap(void *Ptr)
 {
        tHeapHead       *head;
        if((Uint)Ptr < (Uint)gHeapStart)        return 0;
        if((Uint)Ptr > (Uint)gHeapEnd)  return 0;
+       if((Uint)Ptr & (sizeof(Uint)-1))        return 0;
        
        head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
        if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
@@ -403,7 +427,7 @@ int IsHeap(void *Ptr)
 }
 
 #if WARNINGS
-void Heap_Dump()
+void Heap_Dump(void)
 {
        tHeapHead       *head;
        tHeapFoot       *foot;
@@ -412,31 +436,32 @@ void Heap_Dump()
        while( (Uint)head < (Uint)gHeapEnd )
        {               
                foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
-               Log("%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
-               Log("%p 0x%lx", foot->Head, foot->Magic);
-               Log("");
+               Log_Log("Heap", "%p (0x%x): 0x%08lx 0x%lx",
+                       head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
+               Log_Log("Heap", "%p 0x%lx", foot->Head, foot->Magic);
+               Log_Log("Heap", "");
                
                // Sanity Check Header
                if(head->Size == 0) {
-                       Log("HALTED - Size is zero");
+                       Log_Warning("Heap", "HALTED - Size is zero");
                        break;
                }
                if(head->Size & (BLOCK_SIZE-1)) {
-                       Log("HALTED - Size is malaligned");
+                       Log_Warning("Heap", "HALTED - Size is malaligned");
                        break;
                }
                if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
-                       Log("HALTED - Head Magic is Bad");
+                       Log_Warning("Heap", "HALTED - Head Magic is Bad");
                        break;
                }
                
                // Check footer
                if(foot->Magic != MAGIC_FOOT) {
-                       Log("HALTED - Foot Magic is Bad");
+                       Log_Warning("Heap", "HALTED - Foot Magic is Bad");
                        break;
                }
                if(head != foot->Head) {
-                       Log("HALTED - Footer backlink is invalid");
+                       Log_Warning("Heap", "HALTED - Footer backlink is invalid");
                        break;
                }
                
@@ -446,6 +471,94 @@ void Heap_Dump()
 }
 #endif
 
+#if 1
+void Heap_Stats(void)
+{
+       tHeapHead       *head;
+        int    nBlocks = 0;
+        int    nFree = 0;
+        int    totalBytes = 0;
+        int    freeBytes = 0;
+        int    maxAlloc=0, minAlloc=-1;
+        int    avgAlloc, frag, overhead;
+       
+       for(head = gHeapStart;
+               (Uint)head < (Uint)gHeapEnd;
+               head = (void*)( (Uint)head + head->Size )
+               )
+       {
+               nBlocks ++;
+               totalBytes += head->Size;
+               if( head->Magic == MAGIC_FREE )
+               {
+                       nFree ++;
+                       freeBytes += head->Size;
+               }
+               else {
+                       if(maxAlloc < head->Size)       maxAlloc = head->Size;
+                       if(minAlloc == -1 || minAlloc > head->Size)
+                               minAlloc = head->Size;
+               }
+       }
+
+       Log_Log("Heap", "%i blocks (0x%x bytes)", nBlocks, totalBytes);
+       Log_Log("Heap", "%i free blocks (0x%x bytes)", nFree, freeBytes);
+       frag = (nFree-1)*10000/nBlocks;
+       Log_Log("Heap", "%i.%02i%% Heap Fragmentation", frag/100, frag%100);
+       avgAlloc = (totalBytes-freeBytes)/(nBlocks-nFree);
+       overhead = (sizeof(tHeapFoot)+sizeof(tHeapHead))*10000/avgAlloc;
+       Log_Log("Heap", "Average allocation: %i bytes, Average Overhead: %i.%02i%%",
+               avgAlloc, overhead/100, overhead%100
+               );
+       Log_Log("Heap", "Smallest Block: %i bytes, Largest: %i bytes", 
+               minAlloc, maxAlloc);
+       
+       // Scan and get distribution
+       #if 1
+       {
+               struct {
+                       Uint    Size;
+                       Uint    Count;
+               }       sizeCounts[nBlocks];
+                int    i;
+               
+               memset(sizeCounts, 0, nBlocks*sizeof(sizeCounts[0]));
+               
+               for(head = gHeapStart;
+                       (Uint)head < (Uint)gHeapEnd;
+                       head = (void*)( (Uint)head + head->Size )
+                       )
+               {
+                       for( i = 0; i < nBlocks; i ++ ) {
+                               if( sizeCounts[i].Size == 0 )
+                                       break;
+                               if( sizeCounts[i].Size == head->Size )
+                                       break;
+                       }
+                       // Should never reach this part (in a non-concurrent case)
+                       if( i == nBlocks )      continue;
+                       sizeCounts[i].Size = head->Size;
+                       sizeCounts[i].Count ++;
+                       #if 1
+                       //Log("Heap_Stats: %i %p - 0x%x bytes (%s) (%i)", nBlocks, head,
+                       //      head->Size, (head->Magic==MAGIC_FREE?"FREE":"used"), i
+                       //      );
+                       //Log("Heap_Stats: sizeCounts[%i] = {Size:0x%x, Count: %i}", i,
+                       //      sizeCounts[i].Size, sizeCounts[i].Count);
+                       #endif
+               }
+               
+               for( i = 0; i < nBlocks && sizeCounts[i].Count; i ++ )
+               {
+                       Log("Heap_Stats: 0x%x - %i blocks",
+                               sizeCounts[i].Size, sizeCounts[i].Count
+                               );
+               }
+       }
+       #endif
+}
+#endif
+
 // === EXPORTS ===
 EXPORT(malloc);
 EXPORT(realloc);

UCC git Repository :: git.ucc.asn.au