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