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

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