/*---------------------------------------------------------------------------* * pmemblock.c * * * * Copyright 2007, 2008 Nuance Communciations, Inc. * * * * Licensed under the Apache License, Version 2.0 (the 'License'); * * you may not use this file except in compliance with the License. * * * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an 'AS IS' BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * *---------------------------------------------------------------------------*/ #include "pmemory.h" #include "ptypes.h" #if PORTABLE_MEM_MGR == PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR #ifdef PSOSIM #define PSOS #endif #ifdef PSOS #include <stdlib.h> #include <psos.h> #endif #ifdef __cplusplus extern "C" { #endif /* Data *****************************************************************/ #define NUM_POOL_BINS 32 #define NUM_POOL_SLOTS 8 typedef struct memory_pools { uint32 currentNumberOfPools; struct pool_info { unsigned long poolId; void* pMemory; unsigned long size; } poolInfo[NUM_POOL_SLOTS]; } MEMORY_POOL; static MEMORY_POOL memoryPool[NUM_POOL_BINS]; #define NUM_TRACKING_BINS NUM_POOL_BINS /* Object tracking variables */ static struct tracking_struct { uint32 sCurrentAllocationSize; uint32 sMaximumAllocationSize; uint32 sTotalAllocationSize; uint32 sCurrentAllocRealSize; uint32 sMaximumAllocRealSize; uint32 sTotalAllocRealSize; uint32 sCurrentAllocationNumber; uint32 sMaximumAllocationNumber; uint32 sTotalAllocationNumber; uint32 sCurrentAllocationNumberArray[NUM_TRACKING_BINS]; uint32 sMaximumAllocationNumberArray[NUM_TRACKING_BINS]; uint32 sTotalAllocationNumberArray[NUM_TRACKING_BINS]; uint32 sCurrentAllocationSizeArray[NUM_TRACKING_BINS]; uint32 sMaximumAllocationSizeArray[NUM_TRACKING_BINS]; uint32 sTotalAllocationSizeArray[NUM_TRACKING_BINS]; } gMemoryTracking; /* Functions *********************************************************/ static uint32 findBin(size_t size) { int i, bin; for (i = 0, bin = 1; i < NUM_TRACKING_BINS; i++, bin <<= 1) { if ((int)size <= bin) return i; } return 0; } static void MemoryTrackingInit(void) { int i; /* Initialization of object tracking variables */ gMemoryTracking.sCurrentAllocationSize = 0; gMemoryTracking.sMaximumAllocationSize = 0; gMemoryTracking.sTotalAllocationSize = 0; gMemoryTracking.sCurrentAllocationNumber = 0; gMemoryTracking.sMaximumAllocationNumber = 0; gMemoryTracking.sTotalAllocationNumber = 0; gMemoryTracking.sCurrentAllocRealSize = 0; gMemoryTracking.sMaximumAllocRealSize = 0; gMemoryTracking.sTotalAllocRealSize = 0; for (i = 0; i < NUM_TRACKING_BINS; i++) { gMemoryTracking.sCurrentAllocationNumberArray[i] = 0; gMemoryTracking.sMaximumAllocationNumberArray[i] = 0; gMemoryTracking.sTotalAllocationNumberArray[i] = 0; gMemoryTracking.sCurrentAllocationSizeArray[i] = 0; gMemoryTracking.sMaximumAllocationSizeArray[i] = 0; gMemoryTracking.sTotalAllocationSizeArray[i] = 0; } } static void MemoryTrackingAdd(size_t size) { /* Memory tracking code */ uint32 bin = findBin(size); uint32 binsize = 1 << bin; uint32 dummy; /* for breakpoint setting */ #ifdef PSOSIM if (bin == 0) dummy = 0; if (bin == 1) dummy = 0; if (bin == 2) dummy = 0; if (bin == 3) dummy = 0; if (bin == 4) dummy = 0; if (bin == 5) dummy = 0; if (bin == 6) dummy = 0; if (bin == 7) dummy = 0; if (bin == 8) dummy = 0; if (bin == 9) dummy = 0; if (bin == 10) dummy = 0; if (bin == 11) dummy = 0; if (bin == 12) dummy = 0; if (bin == 13) dummy = 0; if (bin == 14) dummy = 0; if (bin == 15) dummy = 0; if (bin == 16) dummy = 0; if (bin == 17) dummy = 0; if (bin == 18) dummy = 0; if (bin == 19) dummy = 0; if (bin == 20) dummy = 0; if (bin == 21) dummy = 0; if (bin > 21) dummy = 0; #endif /* PSOSIM */ gMemoryTracking.sCurrentAllocationSize += size; gMemoryTracking.sTotalAllocationSize += size; if (gMemoryTracking.sCurrentAllocationSize > gMemoryTracking.sMaximumAllocationSize) gMemoryTracking.sMaximumAllocationSize = gMemoryTracking.sCurrentAllocationSize; gMemoryTracking.sCurrentAllocRealSize += binsize; gMemoryTracking.sTotalAllocRealSize += binsize; if (gMemoryTracking.sCurrentAllocRealSize > gMemoryTracking.sMaximumAllocRealSize) gMemoryTracking.sMaximumAllocRealSize = gMemoryTracking.sCurrentAllocRealSize; gMemoryTracking.sCurrentAllocationNumber++; gMemoryTracking.sTotalAllocationNumber++; if (gMemoryTracking.sCurrentAllocationNumber > gMemoryTracking.sMaximumAllocationNumber) gMemoryTracking.sMaximumAllocationNumber = gMemoryTracking.sCurrentAllocationNumber; gMemoryTracking.sCurrentAllocationSizeArray[bin] += size; gMemoryTracking.sTotalAllocationSizeArray[bin] += size; if (gMemoryTracking.sCurrentAllocationSizeArray[bin] > gMemoryTracking.sMaximumAllocationSizeArray[bin]) gMemoryTracking.sMaximumAllocationSizeArray[bin] = gMemoryTracking.sCurrentAllocationSizeArray[bin]; gMemoryTracking.sCurrentAllocationNumberArray[bin]++; gMemoryTracking.sTotalAllocationNumberArray[bin]++; if (gMemoryTracking.sCurrentAllocationNumberArray[bin] > gMemoryTracking.sMaximumAllocationNumberArray[bin]) gMemoryTracking.sMaximumAllocationNumberArray[bin] = gMemoryTracking.sCurrentAllocationNumberArray[bin]; } static void MemoryTrackingDelete(unsigned long size) { /* Memory tracking code */ uint32 bin = findBin(size); uint32 binsize = 1 << bin; gMemoryTracking.sCurrentAllocationSize -= size; gMemoryTracking.sCurrentAllocationNumber--; gMemoryTracking.sCurrentAllocationSizeArray[bin] -= size; gMemoryTracking.sCurrentAllocationNumberArray[bin]--; gMemoryTracking.sCurrentAllocRealSize -= binsize; } static void InitPools(void) { int i, j; for (i = 0; i < NUM_POOL_BINS; i++) { memoryPool[i].currentNumberOfPools = 0; for (j = 0; j < NUM_POOL_SLOTS; j++) { memoryPool[i].poolInfo[j].poolId = 0; memoryPool[i].poolInfo[j].pMemory = NULL; memoryPool[i].poolInfo[j].size = 0; } } } static void TermPools(void) { int i, j; /* For some reason, deleting the region then freeing the memory causes a failure */ /* TODO: Figure out why??? */ for (i = 1; i < NUM_POOL_BINS; i++) { for (j = 0; j < (int)memoryPool[i].currentNumberOfPools; j++) { if (memoryPool[i].poolInfo[j].pMemory != NULL) { unsigned long retval = pt_delete(memoryPool[i].poolInfo[j].poolId); PORT_ASSERT(retval == 0); PORT_ASSERT_GOOD_WRITE_POINTER(memoryPool[i].poolInfo[j].pMemory); free(memoryPool[i].poolInfo[j].pMemory); memoryPool[i].poolInfo[j].poolId = 0; memoryPool[i].poolInfo[j].pMemory = NULL; memoryPool[i].poolInfo[j].size = 0; } } memoryPool[i].currentNumberOfPools = 0; } } #define PARTITION_CONTROL_BLOCK_SIZE 0x400 static BOOL CreatePool(uint32 whichPool, uint32 poolSize) { static uint32 poolNumber = 0; void* pMemory = NULL; unsigned long poolId, unused; uint32 currentNumberOfPools = memoryPool[whichPool].currentNumberOfPools; PORT_ASSERT((whichPool >= 0) && (whichPool < NUM_POOL_BINS)); if (currentNumberOfPools == NUM_POOL_SLOTS) return FALSE; if (whichPool < 2) { /* Invalid partition size */ return FALSE; } else { char name[5]; unsigned long retval; pMemory = malloc(poolSize * (1 << whichPool) + PARTITION_CONTROL_BLOCK_SIZE); PORT_ASSERT_GOOD_WRITE_POINTER(pMemory); /* No memory protection */ if (pMemory == NULL) { /* No memory left in system */ return FALSE; } sprintf(name, "DP%02d", poolNumber); retval = pt_create(name, pMemory, 0, poolSize * (1 << whichPool) + PARTITION_CONTROL_BLOCK_SIZE, 1 << whichPool, PT_LOCAL | PT_DEL, &poolId, &unused); if (retval != 0) { /* Unable to create a pSOS partition */ return FALSE; } } memoryPool[whichPool].poolInfo[currentNumberOfPools].poolId = poolId; memoryPool[whichPool].poolInfo[currentNumberOfPools].pMemory = pMemory; memoryPool[whichPool].poolInfo[currentNumberOfPools].size = poolSize; memoryPool[whichPool].currentNumberOfPools++; poolNumber++; return TRUE; } static BOOL AddPool(uint32 whichPool, uint32 poolSize) { if (memoryPool[whichPool].poolInfo[0].pMemory == NULL) return FALSE; return CreatePool(whichPool, poolSize); } static void* AllocateFromPsos(uint32 whichPool, uint32 poolIndex, uint32 size) { uint32 retval; void* pMemory; PORT_ASSERT(memoryPool[whichPool].poolInfo[poolIndex].poolId); retval = pt_getbuf(memoryPool[whichPool].poolInfo[poolIndex].poolId, &pMemory); /* If we got memory, then return */ if (retval == 0) { PORT_ASSERT_GOOD_WRITE_POINTER(pMemory); *((unsigned long *)pMemory) = (whichPool << 27) + (poolIndex << 24) + size; return (unsigned long *)pMemory + 1; } else return NULL; } static void* SearchPoolsForMemory(uint32 whichPool, uint32 size) { void* pMemory; uint32 poolIndex; /* Get memory from main region */ if (whichPool == 0) { pMemory = malloc(size); /* No memory protection */ if (pMemory == NULL) { /* No memory left in system */ return NULL; } PORT_ASSERT_GOOD_WRITE_POINTER(pMemory); *((unsigned long *)pMemory) = (whichPool << 27) + size; return (unsigned long *)pMemory + 1; } /* Allocate memory from the first available bin (partition) */ for (poolIndex = 0; poolIndex < memoryPool[whichPool].currentNumberOfPools; poolIndex++) { pMemory = AllocateFromPsos(whichPool, poolIndex, size); if (pMemory != NULL) return pMemory; } /* Made it here because we ran out of memory in the pool, so try to add more pools */ if (AddPool(whichPool, memoryPool[whichPool].poolInfo[0].size >> 1) == FALSE) { /* All pools of this size have been consumed */ return NULL; } /* Allocate memory from newly created pool */ pMemory = AllocateFromPsos(whichPool, memoryPool[whichPool].currentNumberOfPools - 1, size); if (pMemory != NULL) return pMemory; /* If we can't allocate from the newly created pool, then we have problems */ /* No memory protection */ /* No memory left in system */ return NULL; } void* PortMemBlockAllocateFromPool(uint32 size) { void* pMemory = NULL; int poolIndex; BOOL foundPool = FALSE; uint32 whichPool; PORT_ASSERT((size & 0xff000000) == 0); size += 4; whichPool = findBin(size); /* Add 4 so I can store info with data */ MemoryTrackingAdd(size); /* If pool exists for the size needed, then use it, else find next largest pool */ for (poolIndex = whichPool; poolIndex < 32; poolIndex++) if (memoryPool[poolIndex].poolInfo[0].pMemory != NULL) { foundPool = TRUE; whichPool = poolIndex; break; } /* If next largest pool doesn't exist, then use pool 0 (regions) */ if (!foundPool) whichPool = 0; /* Allocate memory from the first available bin */ pMemory = SearchPoolsForMemory(whichPool, size); PORT_ASSERT_GOOD_WRITE_POINTER(pMemory); return pMemory; } void PortMemBlockDeleteFromPool(void* pMemory) { unsigned long *pRealMemory = (unsigned long *)pMemory - 1; uint32 whichPool = (*pRealMemory >> 27) & 0x0000001f; uint32 whichBin = (*pRealMemory >> 24) & 0x00000007; PORT_ASSERT_GOOD_WRITE_POINTER(pMemory); MemoryTrackingDelete(*pRealMemory & 0x00ffffff); if (whichPool == 0) { free(pRealMemory); } else { uint32 retval = pt_retbuf(memoryPool[whichPool].poolInfo[whichBin].poolId, pRealMemory); PORT_ASSERT(retval == 0); } } /* PortMemGetPoolSize() : return size of portable memory pool, or 0 if * unknown. */ int PortMemBlockGetPoolSize(void) { return 0; /* TODO: Find size of pool: 4Mar02 */ } /* PortMemBlockSetPoolSize() : set size of portable memory pool on PSOS. * This must be called before PortMemoryInit(), which is called by PortInit(). */ void PortMemBlockSetPoolSize(size_t sizeInBytes) {} int PortMemBlockInit(void) { InitPools(); CreatePool(findBin(1 << 3), 3000); CreatePool(findBin(1 << 4), 10000); CreatePool(findBin(1 << 5), 8000); CreatePool(findBin(1 << 6), 16000); CreatePool(findBin(1 << 7), 5000); CreatePool(findBin(1 << 8), 1000); CreatePool(findBin(1 << 9), 2000); CreatePool(findBin(1 << 10), 50); CreatePool(findBin(1 << 11), 20); CreatePool(findBin(1 << 12), 24); CreatePool(findBin(1 << 13), 16); CreatePool(findBin(1 << 14), 10); CreatePool(findBin(1 << 15), 16); CreatePool(findBin(1 << 16), 4); CreatePool(findBin(1 << 18), 6); MemoryTrackingInit(); } void PortMemBlockTerm(void) { TermPools(); } void PortMemBlockTrackDump(void) { int i; printf("\nCurrent Memory Usage = %d\nMaximum Memory Usage = %d\nTotal Memory Allocation = %d\n\n", gMemoryTracking.sCurrentAllocationSize, gMemoryTracking.sMaximumAllocationSize, gMemoryTracking.sTotalAllocationSize); printf("\nCurrent Real Memory Usage = %d\nMaximum Real Memory Usage = %d\nTotal Real Memory Allocation = %d\n\n", gMemoryTracking.sCurrentAllocRealSize, gMemoryTracking.sMaximumAllocRealSize, gMemoryTracking.sTotalAllocRealSize); for (i = 0; i < NUM_TRACKING_BINS; i++) printf("Max size of 2^%2d byte objects = %d\n", i, gMemoryTracking.sMaximumAllocationSizeArray[i]); printf("\nCurrent Memory Objects = %d\nMaximum Memory Objects = %d\nTotal Memory Objects = %d\n\n", gMemoryTracking.sCurrentAllocationNumber, gMemoryTracking.sMaximumAllocationNumber, gMemoryTracking.sTotalAllocationNumber); for (i = 0; i < NUM_TRACKING_BINS; i++) printf("Max number for 2^%2d byte objects = %d\n", i, gMemoryTracking.sMaximumAllocationNumberArray[i]); } /* PortMemBlockGetMaxMemUsed() : return the maximum real memory allocated. * There is another function of the same name in pmalloc.c, for tracking * non-psos block memory. */ int PortMemBlockGetMaxMemUsed(void) { return gMemoryTracking.sMaximumAllocRealSize; } #ifdef __cplusplus } #endif #endif /* PORTABLE_MEM_MGR == PORTABLE_PSOS_BLOCK_SCHEME_MEM_MGR */