Home | History | Annotate | Download | only in src
      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 
    209   void PortMallocInit(void)
    210   {
    211     if (0 == memPoolsInitialised)
    212     {
    213       initAllMemPools();
    214     }
    215   }
    216 
    217 
    218 
    219 
    220 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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