34dd5f2c44d621a161152679fa3c03d25785327f
[tpg/acess2.git] / Kernel / heap.c
1 /*
2  * AcessOS Microkernel Version
3  * heap.c
4  */
5 #include <acess.h>
6 #include <mm_virt.h>
7 #include <heap_int.h>
8
9 #define WARNINGS        1
10 #define DEBUG_TRACE     0
11 #define VERBOSE_DUMP    0
12
13 // === CONSTANTS ===
14 #define HEAP_INIT_SIZE  0x8000  // 32 KiB
15 #define MIN_SIZE        (sizeof(void*))*8       // 8 Machine Words
16 #define POW2_SIZES      0
17 #define COMPACT_HEAP    0       // Use 4 byte header?
18 #define FIRST_FIT       0
19
20 //#define       MAGIC_FOOT      0x2ACE5505
21 //#define       MAGIC_FREE      0xACE55000
22 //#define       MAGIC_USED      0x862B0505      // MAGIC_FOOT ^ MAGIC_FREE
23 #define MAGIC_FOOT      0x544F4F46      // 'FOOT'
24 #define MAGIC_FREE      0x45455246      // 'FREE'
25 #define MAGIC_USED      0x44455355      // 'USED'
26
27 // === PROTOTYPES ===
28 void    Heap_Install(void);
29 void    *Heap_Extend(int Bytes);
30 void    *Heap_Merge(tHeapHead *Head);
31 void    *Heap_Allocate(const char *File, int Line, size_t Bytes);
32 void    *Heap_AllocateZero(const char *File, int Line, size_t Bytes);
33 void    *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes);
34 void    Heap_Deallocate(void *Ptr);
35 void    Heap_Dump(void);
36 void    Heap_Stats(void);
37
38 // === GLOBALS ===
39 tMutex  glHeap;
40 void    *gHeapStart;
41 void    *gHeapEnd;
42
43 // === CODE ===
44 void Heap_Install(void)
45 {
46         gHeapStart      = (void*)MM_KHEAP_BASE;
47         gHeapEnd        = (void*)MM_KHEAP_BASE;
48         Heap_Extend(HEAP_INIT_SIZE);
49 }
50
51 /**
52  * \fn void *Heap_Extend(int Bytes)
53  * \brief Extend the size of the heap
54  */
55 void *Heap_Extend(int Bytes)
56 {
57         Uint    i;
58         tHeapHead       *head = gHeapEnd;
59         tHeapFoot       *foot;
60         
61         // Bounds Check
62         if( (tVAddr)gHeapEnd == MM_KHEAP_MAX )
63                 return NULL;
64         
65         // Bounds Check
66         if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
67                 Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
68                 return NULL;
69         }
70         
71         // Heap expands in pages
72         for(i=0;i<(Bytes+0xFFF)>>12;i++)
73                 MM_Allocate( (tVAddr)gHeapEnd+(i<<12) );
74         
75         // Increas heap end
76         gHeapEnd += i << 12;
77         
78         // Create Block
79         head->Size = (Bytes+0xFFF)&~0xFFF;
80         head->Magic = MAGIC_FREE;
81         foot = (void*)( (Uint)gHeapEnd - sizeof(tHeapFoot) );
82         foot->Head = head;
83         foot->Magic = MAGIC_FOOT;
84         
85         return Heap_Merge(head);        // Merge with previous block
86 }
87
88 /**
89  * \fn void *Heap_Merge(tHeapHead *Head)
90  * \brief Merges two ajacent heap blocks
91  */
92 void *Heap_Merge(tHeapHead *Head)
93 {
94         tHeapFoot       *foot;
95         tHeapFoot       *thisFoot;
96         tHeapHead       *head;
97         
98         //Log("Heap_Merge: (Head=%p)", Head);
99         
100         thisFoot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
101         if((Uint)thisFoot > (Uint)gHeapEnd)     return NULL;
102         
103         // Merge Left (Down)
104         foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
105         if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
106         && foot->Head->Magic == MAGIC_FREE) {
107                 foot->Head->Size += Head->Size; // Increase size
108                 thisFoot->Head = foot->Head;    // Change backlink
109                 Head->Magic = 0;        // Clear old head
110                 Head->Size = 0;
111                 Head = foot->Head;      // Save new head address
112                 foot->Head = NULL;      // Clear central footer
113                 foot->Magic = 0;
114         }
115         
116         // Merge Right (Upwards)
117         head = (void*)( (Uint)Head + Head->Size );
118         if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
119         {
120                 Head->Size += head->Size;
121                 foot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
122                 foot->Head = Head;      // Update Backlink
123                 thisFoot->Head = NULL;  // Clear old footer
124                 thisFoot->Magic = 0;
125                 head->Size = 0;         // Clear old header
126                 head->Magic = 0;
127         }
128         
129         // Return new address
130         return Head;
131 }
132
133 /**
134  * \brief Allocate memory from the heap
135  * \param File  Allocating source file
136  * \param Line  Source line
137  * \param Bytes Size of region to allocate
138  */
139 void *Heap_Allocate(const char *File, int Line, size_t __Bytes)
140 {
141         tHeapHead       *head, *newhead;
142         tHeapFoot       *foot, *newfoot;
143         tHeapHead       *best = NULL;
144         Uint    bestSize = 0;   // Speed hack
145         size_t  Bytes;
146
147         if( __Bytes == 0 ) {
148                 //return NULL;  // TODO: Return a known un-mapped range.
149                 return INVLPTR;
150         }
151         
152         // Get required size
153         #if POW2_SIZES
154         Bytes = __Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot);
155         Bytes = 1UUL << LOG2(__Bytes);
156         #else
157         Bytes = (__Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + MIN_SIZE-1) & ~(MIN_SIZE-1);
158         #endif
159         
160         // Lock Heap
161         Mutex_Acquire(&glHeap);
162         
163         // Traverse Heap
164         for( head = gHeapStart;
165                 (Uint)head < (Uint)gHeapEnd;
166                 head = (void*)((Uint)head + head->Size)
167                 )
168         {
169                 // Alignment Check
170                 #if POW2_SIZES
171                 if( head->Size != 1UUL << LOG2(head->Size) ) {
172                 #else
173                 if( head->Size & (MIN_SIZE-1) ) {
174                 #endif
175                         Mutex_Release(&glHeap); // Release spinlock
176                         #if WARNINGS
177                         Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
178                         Heap_Dump();
179                         #endif
180                         return NULL;
181                 }
182                 
183                 // Check if allocated
184                 if(head->Magic == MAGIC_USED)   continue;
185                 // Error check
186                 if(head->Magic != MAGIC_FREE)   {
187                         Mutex_Release(&glHeap); // Release spinlock
188                         #if WARNINGS
189                         Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic);
190                         Heap_Dump();
191                         #endif
192                         return NULL;
193                 }
194                 
195                 // Size check
196                 if(head->Size < Bytes)  continue;
197                 
198                 // Perfect fit
199                 if(head->Size == Bytes) {
200                         head->Magic = MAGIC_USED;
201                         head->File = File;
202                         head->Line = Line;
203                         Mutex_Release(&glHeap); // Release spinlock
204                         #if DEBUG_TRACE
205                         Log("[Heap   ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size,  __builtin_return_address(0));
206                         #endif
207                         return head->Data;
208                 }
209                 
210                 // Break out of loop
211                 #if FIRST_FIT
212                 best = head;
213                 bestSize = head->Size;
214                 break;
215                 #else
216                 // or check if the block is the best size
217                 if(bestSize > head->Size) {
218                         best = head;
219                         bestSize = head->Size;
220                 }
221                 #endif
222         }
223         
224         // If no block large enough is found, create one
225         if(!best)
226         {
227                 best = Heap_Extend( Bytes );
228                 // Check for errors
229                 if(!best) {
230                         Mutex_Release(&glHeap); // Release spinlock
231                         return NULL;
232                 }
233                 // Check size
234                 if(best->Size == Bytes) {
235                         best->Magic = MAGIC_USED;       // Mark block as used
236                         best->File = File;
237                         best->Line = Line;
238                         Mutex_Release(&glHeap); // Release spinlock
239                         #if DEBUG_TRACE
240                         Log("[Heap   ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
241                         #endif
242                         return best->Data;
243                 }
244         }
245         
246         // Split Block
247         newhead = (void*)( (Uint)best + Bytes );
248         newfoot = (void*)( (Uint)best + Bytes - sizeof(tHeapFoot) );
249         foot = (void*)( (Uint)best + best->Size - sizeof(tHeapFoot) );
250         
251         newfoot->Head = best;   // Create new footer
252         newfoot->Magic = MAGIC_FOOT;
253         newhead->Size = best->Size - Bytes;     // Create new header
254         newhead->Magic = MAGIC_FREE;
255         foot->Head = newhead;   // Update backlink in old footer
256         best->Size = Bytes;             // Update size in old header
257         best->ValidSize = __Bytes;
258         best->Magic = MAGIC_USED;       // Mark block as used
259         best->File = File;
260         best->Line = Line;
261         
262         Mutex_Release(&glHeap); // Release spinlock
263         #if DEBUG_TRACE
264         Log_Debug("Heap", "newhead(%p)->Size = 0x%x", newhead, newhead->Size);
265         Log_Debug("Heap", "Malloc'd %p (0x%x bytes), returning to %s:%i",
266                 best->Data, best->Size, File, Line);
267         #endif
268         return best->Data;
269 }
270
271 /**
272  * \fn void Heap_Deallocate(void *Ptr)
273  * \brief Free an allocated memory block
274  */
275 void Heap_Deallocate(void *Ptr)
276 {
277         tHeapHead       *head;
278         tHeapFoot       *foot;
279         
280         #if DEBUG_TRACE
281         Log_Log("Heap", "free: Ptr = %p", Ptr);
282         Log_Log("Heap", "free: Returns to %p", __builtin_return_address(0));
283         #endif
284         
285         // INVLPTR is returned from Heap_Allocate when the allocation
286         // size is zero.
287         if( Ptr == INVLPTR )    return;
288         
289         // Alignment Check
290         if( (Uint)Ptr & (sizeof(Uint)-1) ) {
291                 Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
292                 return;
293         }
294         
295         // Sanity check
296         if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
297         {
298                 Log_Warning("Heap", "free - Passed a non-heap address (%p < %p < %p)\n",
299                         gHeapStart, Ptr, gHeapEnd);
300                 return;
301         }
302         
303         // Check memory block - Header
304         head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
305         if(head->Magic == MAGIC_FREE) {
306                 Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
307                 return;
308         }
309         if(head->Magic != MAGIC_USED) {
310                 Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)", head, head->Magic);
311                 Log_Notice("Heap", "Allocated %s:%i", head->File, head->Line);
312                 return;
313         }
314         
315         // Check memory block - Footer
316         foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
317         if(foot->Head != head) {
318                 Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)", head, foot->Head);
319                 Log_Notice("Heap", "Allocated %s:%i", head->File, head->Line);
320                 return;
321         }
322         if(foot->Magic != MAGIC_FOOT) {
323                 Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)", head, &foot->Magic, foot->Magic);
324                 Log_Notice("Heap", "Allocated %s:%i", head->File, head->Line);
325                 return;
326         }
327         
328         // Lock
329         Mutex_Acquire( &glHeap );
330         
331         // Mark as free
332         head->Magic = MAGIC_FREE;
333         //head->File = NULL;
334         //head->Line = 0;
335         head->ValidSize = 0;
336         // Merge blocks
337         Heap_Merge( head );
338         
339         // Release
340         Mutex_Release( &glHeap );
341 }
342
343 /**
344  * \brief Increase/Decrease the size of an allocation
345  * \param File  Calling File
346  * \param Line  Calling Line
347  * \param __ptr Old memory
348  * \param __size        New Size
349  */
350 void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size)
351 {
352         tHeapHead       *head = (void*)( (Uint)__ptr-sizeof(tHeapHead) );
353         tHeapHead       *nextHead;
354         tHeapFoot       *foot;
355         Uint    newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+MIN_SIZE-1)&~(MIN_SIZE-1);
356         
357         // Check for reallocating NULL
358         if(__ptr == NULL)       return Heap_Allocate(File, Line, __size);
359         
360         // Check if resize is needed
361         if(newSize <= head->Size)       return __ptr;
362         
363         // Check if next block is free
364         nextHead = (void*)( (Uint)head + head->Size );
365         
366         // Extend into next block
367         if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
368         {
369                 Uint    size = nextHead->Size + head->Size;
370                 foot = (void*)( (Uint)nextHead + nextHead->Size - sizeof(tHeapFoot) );
371                 // Exact Fit
372                 if(size == newSize) {
373                         head->Size = newSize;
374                         head->ValidSize = __size;
375                         head->File = File;
376                         head->Line = Line;
377                         foot->Head = head;
378                         nextHead->Magic = 0;
379                         nextHead->Size = 0;
380                         return __ptr;
381                 }
382                 // Create a new heap block
383                 nextHead = (void*)( (Uint)head + newSize );
384                 nextHead->Size = size - newSize;
385                 nextHead->Magic = MAGIC_FREE;
386                 foot->Head = nextHead;  // Edit 2nd footer
387                 head->Size = newSize;   // Edit first header
388                 head->File = File;
389                 head->Line = Line;
390                 head->ValidSize = __size;
391                 // Create new footer
392                 foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) );
393                 foot->Head = head;
394                 foot->Magic = MAGIC_FOOT;
395                 return __ptr;
396         }
397         
398         // Extend downwards?
399         foot = (void*)( (Uint)head - sizeof(tHeapFoot) );
400         nextHead = foot->Head;
401         if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
402         {
403                 Uint    size = nextHead->Size + head->Size;
404                 // Inexact fit, split things up
405                 if(size > newSize)
406                 {
407                         // TODO
408                         Warning("[Heap   ] TODO: Space efficient realloc when new size is smaller");
409                 }
410                 
411                 // Exact fit
412                 if(size >= newSize)
413                 {
414                         Uint    oldDataSize;
415                         // Set 1st (new/lower) header
416                         nextHead->Magic = MAGIC_USED;
417                         nextHead->Size = newSize;
418                         nextHead->File = File;
419                         nextHead->Line = Line;
420                         nextHead->ValidSize = __size;
421                         // Get 2nd (old) footer
422                         foot = (void*)( (Uint)nextHead + newSize );
423                         foot->Head = nextHead;
424                         // Save old data size
425                         oldDataSize = head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead);
426                         // Clear old header
427                         head->Size = 0;
428                         head->Magic = 0;
429                         // Copy data
430                         memcpy(nextHead->Data, __ptr, oldDataSize);
431                         // Return
432                         return nextHead->Data;
433                 }
434                 // On to the expensive then
435         }
436         
437         // Well, darn
438         nextHead = Heap_Allocate( File, Line, __size );
439         nextHead -= 1;
440         nextHead->File = File;
441         nextHead->Line = Line;
442         nextHead->ValidSize = __size;
443         
444         memcpy(
445                 nextHead->Data,
446                 __ptr,
447                 head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead)
448                 );
449         
450         free(__ptr);
451         
452         return nextHead->Data;
453 }
454
455 /**
456  * \fn void *Heap_AllocateZero(const char *File, int Line, size_t Bytes)
457  * \brief Allocate and Zero a buffer in memory
458  * \param File  Allocating file
459  * \param Line  Line of allocation
460  * \param Bytes Size of the allocation
461  */
462 void *Heap_AllocateZero(const char *File, int Line, size_t Bytes)
463 {
464         void    *ret = Heap_Allocate(File, Line, Bytes);
465         if(ret == NULL) return NULL;
466         
467         memset( ret, 0, Bytes );
468         
469         return ret;
470 }
471
472 /**
473  * \fn int Heap_IsHeapAddr(void *Ptr)
474  * \brief Checks if an address is a heap pointer
475  */
476 int Heap_IsHeapAddr(void *Ptr)
477 {
478         tHeapHead       *head;
479         if((Uint)Ptr < (Uint)gHeapStart)        return 0;
480         if((Uint)Ptr > (Uint)gHeapEnd)  return 0;
481         if((Uint)Ptr & (sizeof(Uint)-1))        return 0;
482         
483         head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
484         if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
485                 return 0;
486         
487         return 1;
488 }
489
490 /**
491  */
492 void Heap_Validate(void)
493 {
494         Heap_Dump();
495 }
496
497 #if WARNINGS
498 void Heap_Dump(void)
499 {
500         tHeapHead       *head, *badHead;
501         tHeapFoot       *foot = NULL;
502         
503         head = gHeapStart;
504         while( (Uint)head < (Uint)gHeapEnd )
505         {               
506                 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
507                 #if VERBOSE_DUMP
508                 Log_Log("Heap", "%p (0x%llx): 0x%08lx (%i) %4C",
509                         head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
510                 Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
511                 if(head->File) {
512                         Log_Log("Heap", "%sowned by %s:%i",
513                                 (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line);
514                 }
515                 #endif
516                 
517                 // Sanity Check Header
518                 if(head->Size == 0) {
519                         Log_Warning("Heap", "HALTED - Size is zero");
520                         break;
521                 }
522                 if(head->Size & (MIN_SIZE-1)) {
523                         Log_Warning("Heap", "HALTED - Size is malaligned");
524                         break;
525                 }
526                 if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
527                         Log_Warning("Heap", "HALTED - Head Magic is Bad");
528                         break;
529                 }
530                 
531                 // Check footer
532                 if(foot->Magic != MAGIC_FOOT) {
533                         Log_Warning("Heap", "HALTED - Foot Magic is Bad");
534                         break;
535                 }
536                 if(head != foot->Head) {
537                         Log_Warning("Heap", "HALTED - Footer backlink is invalid");
538                         break;
539                 }
540                 
541                 #if VERBOSE_DUMP
542                 Log_Log("Heap", "");
543                 #endif
544                 
545                 // All OK? Go to next
546                 head = foot->NextHead;
547         }
548         
549         // If the heap is valid, ok!
550         if( (tVAddr)head == (tVAddr)gHeapEnd )
551                 return ;
552         
553         // Check for a bad return
554         if( (tVAddr)head >= (tVAddr)gHeapEnd )
555                 return ;
556
557         #if !VERBOSE_DUMP
558         Log_Log("Heap", "%p (0x%llx): 0x%08lx (%i) %4C",
559                 head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
560         Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
561         if(head->File) {
562                 Log_Log("Heap", "%sowned by %s:%i",
563                         (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line);
564         }
565         Log_Log("Heap", "");
566         #endif
567         
568         
569         badHead = head;
570         
571         // Work backwards
572         foot = (void*)( (tVAddr)gHeapEnd - sizeof(tHeapFoot) );
573         Log_Log("Heap", "==== Going Backwards ==== (from %p)", foot);
574         head = foot->Head;
575         while( (tVAddr)head >= (tVAddr)badHead )
576         {
577                 Log_Log("Heap", "%p (0x%llx): 0x%08lx %i %4C",
578                         head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
579                 Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
580                 if(head->File)
581                         Log_Log("Heap", "%sowned by %s:%i",
582                                 (head->Magic!=MAGIC_USED?"was ":""),
583                                 head->File, head->Line);
584                 Log_Log("Heap", "");
585                 
586                 // Sanity Check Header
587                 if(head->Size == 0) {
588                         Log_Warning("Heap", "HALTED - Size is zero");
589                         break;
590                 }
591                 if(head->Size & (MIN_SIZE-1)) {
592                         Log_Warning("Heap", " - Size is malaligned (&0x%x)", ~(MIN_SIZE-1));
593                         break ;
594                 }
595                 if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
596                         Log_Warning("Heap", "HALTED - Head Magic is Bad");
597                         break;
598                 }
599                 
600                 // Check footer
601                 if(foot->Magic != MAGIC_FOOT) {
602                         Log_Warning("Heap", "HALTED - Foot Magic is Bad");
603                         break;
604                 }
605                 if(head != foot->Head) {
606                         Log_Warning("Heap", "HALTED - Footer backlink is invalid");
607                         break;
608                 }
609                 
610                 if(head == badHead)     break;
611                 
612                 foot = (void*)( (tVAddr)head - sizeof(tHeapFoot) );
613                 head = foot->Head;
614                 Log_Debug("Heap", "head=%p", head);
615         }
616         
617         Panic("Heap_Dump - Heap is corrupted, kernel panic!");
618 }
619 #endif
620
621 #if 1
622 void Heap_Stats(void)
623 {
624         tHeapHead       *head;
625          int    nBlocks = 0;
626          int    nFree = 0;
627          int    totalBytes = 0;
628          int    freeBytes = 0;
629          int    maxAlloc=0, minAlloc=-1;
630          int    avgAlloc, frag, overhead;
631         
632         for(head = gHeapStart;
633                 (Uint)head < (Uint)gHeapEnd;
634                 head = (void*)( (Uint)head + head->Size )
635                 )
636         {       
637                 nBlocks ++;
638                 totalBytes += head->Size;
639                 if( head->Magic == MAGIC_FREE )
640                 {
641                         nFree ++;
642                         freeBytes += head->Size;
643                 }
644                 else if( head->Magic == MAGIC_USED) {
645                         if(maxAlloc < head->Size)       maxAlloc = head->Size;
646                         if(minAlloc == -1 || minAlloc > head->Size)
647                                 minAlloc = head->Size;
648                 }
649                 else {
650                         Log_Warning("Heap", "Magic on %p invalid, skipping remainder of heap", head);
651                         break;
652                 }
653                 
654                 // Print the block info?
655                 #if 1
656                 Log_Debug("Heap", "%p - 0x%x (%i) Owned by %s:%i",
657                         head, head->Size, head->ValidSize, head->File, head->Line);
658                 #endif
659         }
660
661         Log_Log("Heap", "%i blocks (0x%x bytes)", nBlocks, totalBytes);
662         Log_Log("Heap", "%i free blocks (0x%x bytes)", nFree, freeBytes);
663         frag = (nFree-1)*10000/nBlocks;
664         Log_Log("Heap", "%i.%02i%% Heap Fragmentation", frag/100, frag%100);
665         avgAlloc = (totalBytes-freeBytes)/(nBlocks-nFree);
666         overhead = (sizeof(tHeapFoot)+sizeof(tHeapHead))*10000/avgAlloc;
667         Log_Log("Heap", "Average allocation: %i bytes, Average Overhead: %i.%02i%%",
668                 avgAlloc, overhead/100, overhead%100
669                 );
670         Log_Log("Heap", "Smallest Block: %i bytes, Largest: %i bytes", 
671                 minAlloc, maxAlloc);
672         
673         // Scan and get distribution
674         #if 1
675         {
676                 struct {
677                         Uint    Size;
678                         Uint    Count;
679                 }       sizeCounts[nBlocks];
680                  int    i;
681                 
682                 memset(sizeCounts, 0, nBlocks*sizeof(sizeCounts[0]));
683                 
684                 for(head = gHeapStart;
685                         (Uint)head < (Uint)gHeapEnd;
686                         head = (void*)( (Uint)head + head->Size )
687                         )
688                 {
689                         for( i = 0; i < nBlocks; i ++ ) {
690                                 if( sizeCounts[i].Size == 0 )
691                                         break;
692                                 if( sizeCounts[i].Size == head->Size )
693                                         break;
694                         }
695                         // Should never reach this part (in a non-concurrent case)
696                         if( i == nBlocks )      continue;
697                         sizeCounts[i].Size = head->Size;
698                         sizeCounts[i].Count ++;
699                         #if 1
700                         //Log("Heap_Stats: %i %p - 0x%x bytes (%s) (%i)", nBlocks, head,
701                         //      head->Size, (head->Magic==MAGIC_FREE?"FREE":"used"), i
702                         //      );
703                         //Log("Heap_Stats: sizeCounts[%i] = {Size:0x%x, Count: %i}", i,
704                         //      sizeCounts[i].Size, sizeCounts[i].Count);
705                         #endif
706                 }
707                 
708                 for( i = 0; i < nBlocks && sizeCounts[i].Count; i ++ )
709                 {
710                         Log("Heap_Stats: 0x%x - %i blocks",
711                                 sizeCounts[i].Size, sizeCounts[i].Count
712                                 );
713                 }
714         }
715         #endif
716 }
717 #endif
718
719 // === EXPORTS ===
720 EXPORT(Heap_Allocate);
721 EXPORT(Heap_AllocateZero);
722 EXPORT(Heap_Reallocate);
723 EXPORT(Heap_Deallocate);
724 EXPORT(Heap_IsHeapAddr);

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