X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fheap.c;h=5e6ccfe68070a24400c83fea84b867485bc021ac;hb=8be652c8915e16cd64b0b34c84ca43d9f892ded9;hp=8d1db7d33c69c82f703ff12afeea98dff8dfa6dc;hpb=1842ea1f2aa3a8d712087e616eb511cfc7174471;p=tpg%2Facess2.git diff --git a/Kernel/heap.c b/Kernel/heap.c index 8d1db7d3..5e6ccfe6 100644 --- a/Kernel/heap.c +++ b/Kernel/heap.c @@ -26,6 +26,7 @@ void *Heap_Merge(tHeapHead *Head); void *malloc(size_t Bytes); void free(void *Ptr); void Heap_Dump(void); +void Heap_Stats(void); // === GLOBALS === tSpinlock glHeap; @@ -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; } @@ -177,7 +178,6 @@ void *malloc(size_t Bytes) #if DEBUG_TRACE Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size, __builtin_return_address(0)); #endif - RELEASE(&glHeap); return head->Data; } @@ -207,10 +207,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("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0)); #endif - RELEASE(&glHeap); // Release spinlock return best->Data; } } @@ -471,6 +471,94 @@ void Heap_Dump(void) } #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);