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

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