/*---------------------------------------------------------------------------*
* 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 */