• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*---------------------------------------------------------------------------*
2  *  pmemfixed.c  *
3  *                                                                           *
4  *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5  *                                                                           *
6  *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7  *  you may not use this file except in compliance with the License.         *
8  *                                                                           *
9  *  You may obtain a copy of the License at                                  *
10  *      http://www.apache.org/licenses/LICENSE-2.0                           *
11  *                                                                           *
12  *  Unless required by applicable law or agreed to in writing, software      *
13  *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15  *  See the License for the specific language governing permissions and      *
16  *  limitations under the License.                                           *
17  *                                                                           *
18  *---------------------------------------------------------------------------*/
19 
20 
21 
22 #include "pmemory.h"
23 #include "plog.h"
24 
25 #undef malloc
26 #undef calloc
27 #undef realloc
28 #undef free
29 
30 
31 #ifdef PORTABLE_FIXED_SIZE_MEM_BLOCK_SCHEME
32 
33 /*
34     How does the Fixed Size Memory Block Manager Work?
35     The memory manager manages an unlimited number of pools, each containing a linked list
36     of free memory blocks of a fixed size.  The memory pools are ordered in increasing block
37     size, eg. pool # 0 contains 4 byte memory blocks, pool # 1 contains 8, etc.  Each memory
38     block consists of a header and body.  The header (which is currently 8 bytes long) is used
39     to store the address of the next free memory block in the linked list, and to store the
40     memory block's pool ID (this is used by the free function to determine which pool the block
41     originated from).  The body is simply the usable memory.  Whenever the application requests
42     memory of a given size, the memory manager selects the appropriate memory pool which contain
43     blocks large enough to satisfy the request.  The memory manager removes a block from the
44     linked list and returns the address of the memory block body.  If there are no blocks
45     available in the pool, then more blocks are created (if there is memory available); the
46     number created is configurable.  If it is not possible to create more blocks, then the
47     memory manager searches the  remaining pools in the sequence until it finds a free block or
48     it runs out of pools (in this case it will return a null pointer to the calling code).
49 
50     How is the memory space allocated to the fixed block pools?
51     At start-up the memory manager requests one large memory block from the system (the size is
52     defined by #define MEM_SIZE).  This memory is used to a) create the fixed size memory pools
53     (each contain the initial number defined in the code) and b) to create extra memory blocks
54     each time a particular pool has been exhausted (the number created is configurable for each
55     memory pool also).  Once all of this memory has been used up it is also possible to make
56     further requests to the system for more memory (to create more fixed memory blocks); this
57     feature is switched on using the compilation flag ALLOW_ADDITIONAL_SYS_MEM_ALLOCS.  Note
58     that once memory blocks have been added to a memory pool they cannot be removed and reused
59     in another, eg a 0.5 MByte memory block could not be removed from its 0.5 Mbyte pool in
60     order to create smaller 4 byte blocks in the 4byte block pool.
61 
62     How is the large memory block from the system allocated?
63     It can be allocated in one of three ways depending on compile time definitions.  If you define
64     STATIC_MEMORY_POOL, it's allocated as a static array.  If you define RTXC_PARTITION_MEMORY,
65     it's allocated from the HEAP_MAP memory partition.  If you don't define anything, it's allocated
66     using the system malloc call.  Of course, RTXC_PARTITION should only be defined on when you building
67     for the RTXC operating system.
68 
69     If STATIC_MEMORY_POOL or RTXC_PARTITION is defined, you cannot define ALLOW_ADDITIONAL_SYS_MEM_ALLOCS.
70 
71     Key Points:
72     1. Configurable memory block sizes (not restricted to power of 2 sizes).
73     2. Best fit algorith.
74     3. Dynamically increases the pool sizes (from an initial number).
75     4. Can limit the total heap size.
76     5. Configurable initial pool sizes.
77     6. Allow additional system memory allocations in order to increase the pool sizes when the
78        'heap' limit has been reached.
79     7. Doesn't support block consolidation, and reuse across pools.
80 
81 */
82 
83 /*************************** Header Files *************************************/
84 
85 #ifdef RTXC_PARTITION_MEMORY
86 #include <rtxcapi.h>
87 /* TODO - When rtxcgen is run, it will create this header file that should contain
88  * identifiers for various memory partitions that we will be using.  For now, in order
89  * to get a compile, define a partition identifier.
90  */
91 #define HEAP_MAP 1
92 
93 #endif
94 
95 #ifdef __cplusplus
96 extern "C"
97 {
98 #endif
99 
100 
101 
102   /*************************** Macros Definitions *******************************/
103   /* All of these should be defined on the command line
104    * #define MEM_MGR_STATS
105    * #define ALLOW_ADDITIONAL_SYS_MEM_ALLOCS
106    * #define ALLOW_POOL_GROWTHS
107    * #define MEM_SIZE
108    */
109 
110   /*
111   #if (defined(STATIC_MEMORY_POOL) || defined(RTXC_PARTITION_MEMORY)) && defined(ALLOW_ADDITIONAL_SYS_MEM_ALLOCS)
112   #error Can't allocate additional memory blocks from the system.
113   #endif
114   */
115   /* TODO: Need to figure out a good size for this. */
116   /* This had better be the same as the block in HEAP_MAP as defined when building RTXC. */
117 
118 #ifndef MEM_SIZE
119   /* If not defined on the command line, use a default value of 10 megabytes for the heap. */
120 #define MEM_SIZE       (10 * 1024 * 1024)      /* 10 MBytes */
121 #endif
122 
123 #define MEM_BLOCK_HDR           8   /* (bytes): 16 bit Pool ID, 16 bit signature, 32 bit next block pointer */
124 #define MEM_POOL_ID_OFFSET      0
125 #define NEXT_BLOCK_PTR_OFFSET   1   /* (no. of 4 byte words) */
126 #define MEM_BLOCK_HDR_OFFSET    2   /* (no. of 4 byte words) */
127 
128 #define MEM_POOL_ID_MASK        0x000000FF
129 #define MEM_REQ_SIZE_MASK       0xFFFFFF00
130 #define MEM_REQ_SIZE_BIT_SHIFT  8
131 
132 
133 
134   /*************************** Type Defs ****************************************/
135 
136   typedef struct
137   {
138     unsigned int accReqSize;
139     unsigned int maxReqSize;
140     unsigned int allocated;
141     unsigned int accAllocated;
142     unsigned int accFreed;
143     unsigned int max_alloc;
144   }
145   MEM_STATS;
146 
147 
148 
149   /*************************** Global Variables *********************************/
150 
151   int memPoolsInitialised = 0;
152 
153   unsigned int memBlockSize[]    = {     4,    8,    12,    16,    20,    24,    28,    32,    36,    40,    44,    48,    52,    56,    60,    64,  128,   256,   512,  1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288 };
154   /*unsigned int memBlockNum[]     = {   400, 1600, 17000,  8192, 13440,   512,   384,  4352,   900,  7000,   256,  2048,  1024,   128,   128,   256, 6000,  2500,   380,   170,   85,   40,   30,   120,    40,     2,      1,      2,      2 };*/
155   unsigned int memBlockNum[]     = {     0,    0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,     0,    0,     0,     0,     0,    0,    0,    0,     0,     0,     0,      0,      0,      0 };
156   unsigned int memBlkGrowthNum[] = {   128,  128,   128,   128,   128,   128,   128,   128,   128,   128,   128,   128,   128,   128,   128,   128,  128,   128,     1,     1,    1,    1,    1,     1,     1,     1,      1,      1,      1 };
157 
158 #define NUM_OF_POOLS        (sizeof( memBlockSize ) / sizeof( unsigned int ))
159 
160   static unsigned int memBlkGrowths[NUM_OF_POOLS];
161 
162 #ifdef STATIC_MEMORY_POOL
163   static char pHeap[MEM_SIZE];
164 #else
165   static char *pHeap;
166 #endif
167   static char* pReservedHeapMem;
168   static char* pMemPools[NUM_OF_POOLS];
169 
170   static unsigned int initialHeapSize = MEM_SIZE;
171   static unsigned int usedHeapSize = 0;
172   static unsigned int reservedHeapSize = 0;
173   static unsigned int totalSystemAllocMem = 0;
174   static unsigned int numOfSystemAllocs = 0;
175 
176   static MEM_STATS memStats[NUM_OF_POOLS];
177   static unsigned int allocatedMem = 0;
178   static unsigned int maxAllocMem = 0;
179 
180 
181 
182   /*************************** Function Prototypes ******************************/
183 
184   void initAllMemPools(void);
185   char* initMemPool(int poolId, int memBlockSize, int numOfMemBlocks, char** startAddress);
186   void* myMalloc(size_t size);
187   void myFree(void* ptr);
188   void displayMemStats(void);
189   void increaseMemPoolSize(unsigned int poolId);
190 
191 
192 
193   /*************************** Function Definitions *****************************/
194 
195   /*******************************************************************************
196    *
197    * Function:    PortMallocInit
198    *
199    * Args:        void
200    *
201    * Returns:     void
202    *
203    * Description: API function which initialises the fixed size memory pools.  Can
204    *              be called multiple times in a session, but is only effective the
205    *              first time it is called.
206    *
207    *******************************************************************************/
208 
PortMallocInit(void)209   void PortMallocInit(void)
210   {
211     if (0 == memPoolsInitialised)
212     {
213       initAllMemPools();
214     }
215   }
216 
217 
218 
219 
220 
PortMallocGetMaxMemUsed(void)221   int PortMallocGetMaxMemUsed(void)
222   {
223     return (int)maxAllocMem;
224   }
225 
226 
227 
228   /*******************************************************************************
229    *
230    * Function:    PortMallocSetPoolSize
231    *
232    * Args:        Pool size (size_t)
233    *
234    * Returns:     void
235    *
236    * Description: API function used to set the initial heap size. Note this can be
237    *              called at any time, but is only effective if the memory manager
238    *              has not already been initialised.
239    *
240    *******************************************************************************/
241 
PortMallocSetPoolSize(size_t size)242   void PortMallocSetPoolSize(size_t size)
243   {
244 #if !defined(STATIC_MEMORY_POOL) && !defined(RTXC_PARTITION_MEMORY)
245     if (!memPoolsInitialised)
246     {
247       initialHeapSize = (unsigned int)size;
248     }
249 #else
250     (void)size;
251 #endif
252   }
253 
254 
255 
256   /*******************************************************************************
257    *
258    * Function:    PortMallocGetPoolSize
259    *
260    * Args:        void
261    *
262    * Returns:     Pool Size (int)
263    *
264    * Description: API function to return the initial heap size.
265    *
266    *******************************************************************************/
267 
PortMallocGetPoolSize(void)268   int PortMallocGetPoolSize(void)
269   {
270     return (int)initialHeapSize;
271   }
272 
273 
274 
275   /*******************************************************************************
276    *
277    * Function:    initAllMemPools
278    *
279    * Args:        void
280    *
281    * Returns:     void
282    *
283    * Description: Internal function which is used to initialise all of the
284    *              memory pools. Note it can be called many times but is only
285    *              effective the first time it is called.
286    *
287    *******************************************************************************/
288 
initAllMemPools(void)289   void initAllMemPools(void)
290   {
291     char *availableMemStartAddress;
292 
293     if (0 == memPoolsInitialised)
294     {
295       int ii;
296 
297       /* Calculate the required heap size */
298       for (ii = 0; ii < NUM_OF_POOLS; ii++)
299       {
300         usedHeapSize += (memBlockSize[ii] + MEM_BLOCK_HDR) * memBlockNum[ii];
301       }
302 
303       if (initialHeapSize < usedHeapSize)
304       {
305         /* Insuffucient heap memory; abort initialisation */
306         return;
307       }
308 
309 
310 #if defined(STATIC_MEMORY_POOL)
311       /* pHead has already been allocated, statically.  Don't need to do anything. */
312 #elif defined(RTXC_PARTITION_MEMORY)
313       /* Grab the one and only block in HEAP_MAP. */
314       pHeap = KS_alloc(HEAP_MAP);
315       /* MEM_SIZE has better equal the size of HEAP_MAP's block. */
316       PORT_ASSERT(MEM_SIZE == KS_inqmap(HEAP_MAP));
317 #else
318       /* Use the system malloc for heap allocation. */
319 
320       pHeap = (char*)malloc(initialHeapSize);
321 #endif
322       if (0 == pHeap)
323       {
324         /* Unable to get memory for heap; abort initialisation */
325         return;
326       }
327 
328       totalSystemAllocMem = initialHeapSize;
329       numOfSystemAllocs++;
330       reservedHeapSize = initialHeapSize - usedHeapSize;
331 
332       /* Initialise each memory pool */
333       availableMemStartAddress = pHeap;
334 
335       for (ii = 0; ii < NUM_OF_POOLS; ii++)
336       {
337         pMemPools[ii] = 0;
338 
339         if (0 != memBlockNum[ii])
340         {
341           pMemPools[ii] = initMemPool(ii, memBlockSize[ii] + MEM_BLOCK_HDR, memBlockNum[ii], &availableMemStartAddress);
342         }
343       }
344 
345       pReservedHeapMem = availableMemStartAddress;
346 
347       memPoolsInitialised = 1;
348     }
349   }
350 
351 
352 
353   /*******************************************************************************
354    *
355    * Function:    initMemPool
356    *
357    * Args:        Pool ID (int), Memory Block Size (int), Number of Memory Blocks
358    *              (int), Heap Memory Start Address (char**)
359    *
360    * Returns:     Memory Pool Start Address (char*)
361    *
362    * Description: Internal function used to fill a specified memory pool with a
363    *              specified number of memory blocks of a specified size.  The heap
364    *              memory start address is adjusted to point to the next available
365    *              memory following the newly created pool.
366    *
367    *******************************************************************************/
368 
initMemPool(int poolId,int memBlockSize,int numOfMemBlocks,char ** startAddress)369   char* initMemPool(int poolId, int memBlockSize, int numOfMemBlocks, char** startAddress)
370   {
371     char* pPrevMemBlock = 0;
372     char* pCurrMemBlock = 0;
373     char* pStartMemPool = 0;
374     int ii;
375 
376     for (ii = 0; ii < numOfMemBlocks; ii++)
377     {
378       pCurrMemBlock = &((*startAddress)[ii*memBlockSize]);
379 
380       *((unsigned int*)pCurrMemBlock) = poolId;
381 
382       if (0 != pPrevMemBlock)
383       {
384         ((unsigned int*)pPrevMemBlock)[NEXT_BLOCK_PTR_OFFSET] = (unsigned int)pCurrMemBlock;
385       }
386 
387       pPrevMemBlock = pCurrMemBlock;
388     }
389 
390     ((unsigned int*)pPrevMemBlock)[NEXT_BLOCK_PTR_OFFSET] = 0;
391 
392     pStartMemPool = *startAddress;
393 
394     *startAddress = (*startAddress) + (ii * memBlockSize);
395 
396     return pStartMemPool;
397   }
398 
399 
400 
401   /*******************************************************************************
402    *
403    * Function:    PortMalloc
404    *
405    * Args:        Size (size_t)
406    *
407    * Returns:     Pointer to memory block (void*)
408    *
409    * Description: API function which is used by the application to request memory.
410    *              A null pointer is returned if the memory manager is unable to
411    *              satisfy the request.
412    *
413    *******************************************************************************/
414 
PortMalloc(size_t size)415   void* PortMalloc(size_t size)
416   {
417     int poolId;
418     char *pMemBlock;
419     int ii;
420 
421     /* Make sure the memory manager has been initialised */
422     if (0 == memPoolsInitialised)
423     {
424       initAllMemPools();
425     }
426 
427     poolId = NUM_OF_POOLS;
428     pMemBlock = 0;
429 
430     /* Find the best fit memory block */
431     for (ii = 0; ii < NUM_OF_POOLS; ii++)
432     {
433       if (memBlockSize[ii] >= size)
434       {
435         poolId = ii;
436 
437         break;
438       }
439     }
440 
441     /* Ensure that the requested size is not larger than the largest block size */
442     if (NUM_OF_POOLS > poolId)
443     {
444       /* Search the selected memory pool for a memory block; if there are none
445          then try to create some more blocks.  If this is not possible then
446          search the next largest memory block pool.  Repeat until either a block
447          is found, or there are no pools left */
448       for (ii = poolId; ii < NUM_OF_POOLS; ii++)
449       {
450 #ifdef ALLOW_POOL_GROWTHS
451         /* If there are no blocks left, try to create some more */
452         if (0 == pMemPools[ii])
453         {
454           increaseMemPoolSize(ii);
455         }
456 #endif /* ALLOW_POOL_GROWTHS */
457 
458         if (0 != pMemPools[ii])
459         {
460           /* Remove the memory block from the pool linked-list */
461           pMemBlock = pMemPools[ii];
462 
463           pMemPools[ii] = (char*)(((unsigned int*)pMemBlock)[NEXT_BLOCK_PTR_OFFSET]);
464 
465 #ifdef MEM_MGR_STATS
466           /* Record the requested size in the memory block header - this is used
467              by PortFree to determine how much requested memory has been free'd */
468           *((unsigned int*)pMemBlock) = ii | (size << MEM_REQ_SIZE_BIT_SHIFT);
469 #endif /* MEM_MGR_STATS */
470 
471           /* Adjust the memory block pointer to point to the useful portion of the
472              memory block, ie beyond the header */
473           pMemBlock = pMemBlock + MEM_BLOCK_HDR;
474 
475 #ifdef MEM_MGR_STATS
476           /* Update the memory statistics */
477           allocatedMem += size;
478 
479           if (allocatedMem > maxAllocMem)
480           {
481             maxAllocMem = allocatedMem;
482           }
483 
484           memStats[ii].accReqSize += size;
485           memStats[ii].accAllocated++;
486           memStats[ii].allocated++;
487 
488           if (memStats[ii].maxReqSize < size)
489           {
490             memStats[ii].maxReqSize = size;
491           }
492 
493           if (memStats[ii].allocated > memStats[ii].max_alloc)
494           {
495             memStats[ii].max_alloc = memStats[ii].allocated;
496           }
497 #endif /* MEM_MGR_STATS */
498           break;
499         }
500       }
501     }
502 
503     return (void*)pMemBlock;
504   }
505 
506 
507 #ifdef ALLOW_POOL_GROWTHS
508   /*******************************************************************************
509    *
510    * Function:    increaseMemPoolSize
511    *
512    * Args:        Pool ID (unsigned int)
513    *
514    * Returns:     void
515    *
516    * Description: Increases the number of blocks in a given pool by the number
517    *              specified in the array memBlkGrowthNum if there is memory
518    *              available.  Memory is allocated from the heap reserve if
519    *              availabe, else it is requested from the system (if the
520    *              compilation flag ALLOW_ADDITIONAL_SYS_MEM_ALLOCS is defined. If
521    *              there is insufficient memory then the operation is aborted
522    *              without notification to the calling code.
523    *
524    *******************************************************************************/
525 
increaseMemPoolSize(unsigned int poolId)526   void increaseMemPoolSize(unsigned int poolId)
527   {
528     unsigned int requiredMemSize = memBlkGrowthNum[poolId] * (memBlockSize[poolId] + MEM_BLOCK_HDR);
529 
530     /* See if there is enough heap reserve memory */
531     if (requiredMemSize <= reservedHeapSize)
532     {
533       /* We're in luck; there's enough space */
534       pMemPools[poolId] = initMemPool(poolId, memBlockSize[poolId] + MEM_BLOCK_HDR, memBlkGrowthNum[poolId], &pReservedHeapMem);
535 
536       memBlockNum[poolId] += memBlkGrowthNum[poolId];
537 
538       reservedHeapSize -= requiredMemSize;
539       usedHeapSize += requiredMemSize;
540 
541 #ifdef MEM_MGR_STATS
542       memBlkGrowths[poolId]++;
543 #endif /* MEM_MGR_STATS */
544     }
545 #ifdef ALLOW_ADDITIONAL_SYS_MEM_ALLOCS
546     else
547     {
548       /* There's not enough memory in the heap reserve, so request it from the system */
549       char* pStartAddress = (char*)malloc(requiredMemSize);
550 
551       if (0 != pStartAddress)
552       {
553         /* The system has allocated some memory, so let's make some more blocks */
554         pMemPools[poolId] = initMemPool(poolId, memBlockSize[poolId] + MEM_BLOCK_HDR, memBlkGrowthNum[poolId], &pStartAddress);
555 
556         memBlockNum[poolId] += memBlkGrowthNum[poolId];
557 
558         totalSystemAllocMem += requiredMemSize;
559         numOfSystemAllocs++;
560 
561 #ifdef MEM_MGR_STATS
562         memBlkGrowths[poolId]++;
563 #endif /* MEM_MGR_STATS */
564       }
565     }
566 #endif /* ALLOW_ADDITIONAL_SYS_MEM_ALLOCS */
567   }
568 #endif /* ALLOW_POOL_GROWTHS */
569 
570 
571 
572   /*******************************************************************************
573    *
574    * Function:    PortFree
575    *
576    * Args:        Memory Block Pointer (void*)
577    *
578    * Returns:     void
579    *
580    * Description: API function used by the application code to return a memory
581    *              block to the appropriate pool.  Note that this function is not
582    *              able to handle null or stale memory block pointers; calling this
583    *              function under these conditions will result in unpredictable
584    *              behavior.
585    *
586    *******************************************************************************/
587 
PortFree(void * pMem)588   void PortFree(void* pMem)
589   {
590     unsigned int tmpVal;
591     unsigned char poolId;
592     char* pCurrentHead;
593 #ifdef MEM_MGR_STATS
594     unsigned int reqMemSize;
595 #endif
596 
597     /* What is the memory block pool id ? */
598     tmpVal = ((unsigned int*)pMem)[-MEM_BLOCK_HDR_OFFSET+MEM_POOL_ID_OFFSET];
599     poolId = tmpVal & MEM_POOL_ID_MASK;
600 
601     /* Add the memory block to the appropriate pool */
602     pCurrentHead = pMemPools[poolId];
603     ((unsigned int*)pMem)[-MEM_BLOCK_HDR_OFFSET+NEXT_BLOCK_PTR_OFFSET] = (unsigned int)pCurrentHead;
604     pMemPools[poolId] = (char*) & (((unsigned int*)pMem)[-MEM_BLOCK_HDR_OFFSET]);
605 
606 #ifdef MEM_MGR_STATS
607     /* What was the requested memory size ? */
608     reqMemSize = tmpVal >> MEM_REQ_SIZE_BIT_SHIFT;
609 
610     allocatedMem -= reqMemSize;
611 
612     PORT_ASSERT(allocatedMem >= 0);
613 
614     memStats[poolId].accFreed++;
615     memStats[poolId].allocated--;
616 #endif /* MEM_MGR_STATS */
617   }
618 
619 
620 
621   /*******************************************************************************
622    *
623    * Function:    displayMemStats
624    *
625    * Args:        void
626    *
627    * Returns:     void
628    *
629    * Description: API function used to display the overall memory and individual
630    *              memory pool statistics to standard output.
631    *
632    *******************************************************************************/
633 
displayMemStats(void)634   void displayMemStats(void)
635   {
636     unsigned int totBNum = 0;
637     unsigned int totGrowths = 0;
638     unsigned int totAlloc = 0;
639     unsigned int totAccAlloc = 0;
640     unsigned int totAccFreed = 0;
641     unsigned int totMaxAlloc = 0;
642     unsigned int totMemWithOH = 0;
643     unsigned int totMem = 0;
644     unsigned int bytesAllocWithOH = 0;
645     unsigned int bytesAlloc = 0;
646     unsigned int maxBytesAllocWithOH = 0;
647     unsigned int maxBytesAlloc = 0;
648     unsigned int ii;
649 
650     printf("\nPool ID   BlkSz AvReqSz MaxReqSz   NumBlk  Growths    Alloc AccAlloc AccFreed MaxAlloc Alloc(b)  MaxA(b)\n");
651     printf("--------------------------------------------------------------------------------------------------------\n");
652 
653     for (ii = 0; ii < NUM_OF_POOLS; ii++)
654     {
655       unsigned int avReqSize = 0;
656 
657       if (0 != memStats[ii].accAllocated)
658       {
659         avReqSize = memStats[ii].accReqSize / memStats[ii].accAllocated;
660       }
661 
662       printf("   %4i  %6i  %6i   %6i  %7i  %7i  %7i  %7i  %7i  %7i %8i %8i\n", ii, memBlockSize[ii], avReqSize, memStats[ii].maxReqSize, memBlockNum[ii], memBlkGrowths[ii], memStats[ii].allocated, memStats[ii].accAllocated, memStats[ii].accFreed, memStats[ii].max_alloc, (memBlockSize[ii]*memStats[ii].allocated), (memBlockSize[ii]*memStats[ii].max_alloc));
663 
664       totBNum += memBlockNum[ii];
665       totGrowths += memBlkGrowths[ii];
666       totAlloc += memStats[ii].allocated;
667       totAccAlloc += memStats[ii].accAllocated;
668       totAccFreed += memStats[ii].accFreed;
669       totMaxAlloc += memStats[ii].max_alloc;
670 
671       totMemWithOH += (memBlockSize[ii] + MEM_BLOCK_HDR) * memBlockNum[ii];
672       totMem += memBlockSize[ii] * memBlockNum[ii];
673       bytesAllocWithOH += memStats[ii].allocated * (memBlockSize[ii] + MEM_BLOCK_HDR);
674       bytesAlloc += memStats[ii].allocated * memBlockSize[ii];
675       maxBytesAllocWithOH += memStats[ii].max_alloc * (memBlockSize[ii] + MEM_BLOCK_HDR);
676       maxBytesAlloc += memStats[ii].max_alloc * memBlockSize[ii];
677     }
678 
679     printf("--------------------------------------------------------------------------------------------------------\n");
680     printf("Total                             %7i  %7i  %7i  %7i  %7i  %7i %8i %8i\n\n", totBNum, totGrowths, totAlloc, totAccAlloc, totAccFreed, totMaxAlloc, bytesAlloc, maxBytesAlloc);
681     printf("Total Memory     %9i bytes\n", totMemWithOH);
682     printf("Total Memory     %9i bytes (without overhead)\n", totMem);
683     printf("Allocated Memory %9i bytes\n", bytesAllocWithOH);
684     printf("Allocated Memory %9i bytes (without overhead)\n", bytesAlloc);
685     printf("Max Alloc Memory %9i bytes\n", maxBytesAllocWithOH);
686     printf("Max Alloc Memory %9i bytes (without overhead)\n", maxBytesAlloc);
687     printf("\nReq Alloc Memory %9i bytes\n", allocatedMem);
688     printf("Max Rq Alloc Mem %9i bytes\n\n", maxAllocMem);
689 
690     printf("Used Heap Size   %9i bytes\n", usedHeapSize);
691     printf("Reserved Heap    %9i bytes\n", reservedHeapSize);
692     printf("Total Sys Alloc  %9i bytes\n", totalSystemAllocMem);
693     printf("Num of Sys Alloc %9i\n", numOfSystemAllocs);
694 
695     printf("\n");
696   }
697 
698 
699 
700 #ifdef __cplusplus
701 } /* end extern "C" */
702 #endif
703 
704 
705 #endif /* FIXED_SIZE_MEM_BLOCK_SCHEME */
706