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

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