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

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