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

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