X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fheap.c;h=1e7ed464ec812084017b1149bda97a9544a97e6e;hb=6f1c621ed4d24ddbdc863cd5ef684e919c8f8b55;hp=8ceefac1de0ef791a550ab2c1f6f393f2f33e5f0;hpb=d8b11d2074b48f17f999d44c75b1f76fdffd970b;p=tpg%2Facess2.git diff --git a/Kernel/heap.c b/Kernel/heap.c index 8ceefac1..1e7ed464 100644 --- a/Kernel/heap.c +++ b/Kernel/heap.c @@ -10,10 +10,8 @@ #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 @@ -22,12 +20,13 @@ #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; @@ -35,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; @@ -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 @@ -139,6 +137,8 @@ void *malloc(size_t Bytes) // Get required size Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1); + //if(glHeap) + // Debug("glHeap = %i", glHeap); // Lock Heap LOCK(&glHeap); @@ -150,11 +150,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; } @@ -162,11 +162,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; } @@ -208,6 +208,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)); @@ -348,8 +349,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 @@ -363,11 +371,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; } /** @@ -405,7 +429,7 @@ int IsHeap(void *Ptr) } #if WARNINGS -void Heap_Dump() +void Heap_Dump(void) { tHeapHead *head; tHeapFoot *foot; @@ -414,7 +438,8 @@ void Heap_Dump() while( (Uint)head < (Uint)gHeapEnd ) { foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) ); - Log_Log("Heap", "%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic); + 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", ""); @@ -448,6 +473,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);