Commenting is nice
[tpg/acess2.git] / Kernel / heap.c
index 920e9b6..5e6ccfe 100644 (file)
 #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 ===
 tSpinlock      glHeap;
@@ -33,7 +34,7 @@ void  *gHeapStart;
 void   *gHeapEnd;
 
 // === CODE ===
-void Heap_Install()
+void Heap_Install(void)
 {
        gHeapStart      = (void*)MM_KHEAP_BASE;
        gHeapEnd        = (void*)MM_KHEAP_BASE;
@@ -147,11 +148,11 @@ void *malloc(size_t Bytes)
        {
                // Alignment Check
                if( head->Size & (BLOCK_SIZE-1) ) {
+                       RELEASE(&glHeap);       // Release spinlock
                        #if WARNINGS
                        Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
                        Heap_Dump();
                        #endif
-                       RELEASE(&glHeap);
                        return NULL;
                }
                
@@ -159,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
                        Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic);
                        Heap_Dump();
                        #endif
-                       RELEASE(&glHeap);       // Release spinlock
                        return NULL;
                }
                
@@ -205,6 +206,7 @@ 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("[Heap   ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
@@ -425,7 +427,7 @@ int IsHeap(void *Ptr)
 }
 
 #if WARNINGS
-void Heap_Dump()
+void Heap_Dump(void)
 {
        tHeapHead       *head;
        tHeapFoot       *foot;
@@ -469,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