1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/NCollection/NCollection_IncAllocator.cxx

398 lines
13 KiB
C++
Executable File

// File: NCollection_IncAllocator.cxx
// Created: 12.04.02 21:16:26
// Author: Alexander GRIGORIEV
// Copyright: Open Cascade 2002
#include <NCollection_IncAllocator.hxx>
#include <NCollection_DataMap.hxx>
#include <NCollection_Map.hxx>
#include <Standard_Mutex.hxx>
#include <Standard_OutOfMemory.hxx>
#include <stdio.h>
IMPLEMENT_STANDARD_HANDLE (NCollection_IncAllocator,NCollection_BaseAllocator)
IMPLEMENT_STANDARD_RTTIEXT (NCollection_IncAllocator,NCollection_BaseAllocator)
namespace
{
inline size_t IMEM_SIZE (const size_t theSize)
{
return (theSize - 1) / sizeof(NCollection_IncAllocator::aligned_t) + 1;
}
inline size_t IMEM_ALIGN (const void* theAddress)
{
return sizeof(NCollection_IncAllocator::aligned_t) * IMEM_SIZE (size_t(theAddress));
}
#define IMEM_FREE(p_bl) (size_t(p_bl->p_end_block - p_bl->p_free_space))
};
#define MaxLookup 16
static Standard_Boolean IS_DEBUG = Standard_False;
//=======================================================================
/**
* Static data map (address -> AllocatorID)
*/
//=======================================================================
static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
{
static NCollection_DataMap<Standard_Address, Standard_Size> TheMap;
return TheMap;
}
//=======================================================================
/**
* Static map (AllocatorID)
*/
//=======================================================================
static NCollection_Map<Standard_Size>& StorageIDSet()
{
static NCollection_Map<Standard_Size> TheMap;
return TheMap;
}
//=======================================================================
//function : IncAllocator_SetDebugFlag
//purpose : Turn on/off debugging of memory allocation
//=======================================================================
Standard_EXPORT void IncAllocator_SetDebugFlag(const Standard_Boolean theDebug)
{
IS_DEBUG = theDebug;
}
//=======================================================================
/**
* Static value of the current allocation ID. It provides unique
* numbering of allocators.
*/
//=======================================================================
static Standard_Size CurrentID = 0;
static Standard_Size CATCH_ID = 0;
//=======================================================================
//function : Debug_Create
//purpose : Store the allocator address in the internal maps
//=======================================================================
static void Debug_Create(Standard_Address theAlloc)
{
static Standard_Mutex aMutex;
Standard_Boolean isReentrant = Standard::IsReentrant();
if (isReentrant)
aMutex.Lock();
StorageIDMap().Bind(theAlloc, ++CurrentID);
StorageIDSet().Add(CurrentID);
if (isReentrant)
aMutex.Unlock();
if (CurrentID == CATCH_ID)
{
// Place for break point for creation of investigated allocator
int a = 1;
}
}
//=======================================================================
//function : Debug_Destroy
//purpose : Forget the allocator address from the internal maps
//=======================================================================
static void Debug_Destroy(Standard_Address theAlloc)
{
static Standard_Mutex aMutex;
Standard_Boolean isReentrant = Standard::IsReentrant();
if (isReentrant)
aMutex.Lock();
if (StorageIDMap().IsBound(theAlloc))
{
Standard_Size anID = StorageIDMap()(theAlloc);
StorageIDSet().Remove(anID);
StorageIDMap().UnBind(theAlloc);
}
if (isReentrant)
aMutex.Unlock();
}
//=======================================================================
//function : IncAllocator_PrintAlive
//purpose : Outputs the alive numbers to the file inc_alive.d
//=======================================================================
Standard_EXPORT void IncAllocator_PrintAlive()
{
if (!StorageIDSet().IsEmpty())
{
FILE * ff = fopen("inc_alive.d", "wt");
if (ff == NULL)
{
cout << "failure writing file inc_alive.d" << endl;
}
else
{
fprintf(ff, "Alive IncAllocators (number, size in Kb)\n");
NCollection_DataMap<Standard_Address, Standard_Size>::Iterator
itMap(StorageIDMap());
Standard_Size aTotSize = 0;
Standard_Integer nbAlloc = 0;
for (; itMap.More(); itMap.Next())
{
NCollection_IncAllocator* anAlloc =
static_cast<NCollection_IncAllocator*>(itMap.Key());
Standard_Size anID = itMap.Value();
Standard_Size aSize = anAlloc->GetMemSize();
aTotSize += aSize;
nbAlloc++;
fprintf(ff, "%-8d %8.1f\n", anID, double(aSize)/1024);
}
fprintf(ff, "Total:\n%-8d %8.1f\n", nbAlloc, double(aTotSize)/1024);
fclose(ff);
}
}
}
//=======================================================================
//function : NCollection_IncAllocator()
//purpose : Constructor
//=======================================================================
NCollection_IncAllocator::NCollection_IncAllocator (const size_t theBlockSize)
{
#ifdef ALLOC_TRACK_USAGE
printf ("\n..NCollection_IncAllocator: Created (%x)\n",this);
#endif
#ifdef DEB
if (IS_DEBUG)
Debug_Create(this);
#endif
const size_t aSize = IMEM_SIZE(sizeof(IBlock)) +
IMEM_SIZE((theBlockSize > 2*sizeof(IBlock)) ? theBlockSize : 24600);
IBlock * const aBlock = (IBlock *) malloc (aSize * sizeof(aligned_t));
myFirstBlock = aBlock;
mySize = aSize;
myMemSize = aSize * sizeof(aligned_t);
if (aBlock == NULL)
Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
aBlock -> p_free_space = (aligned_t *) IMEM_ALIGN (&aBlock[1]);
aBlock -> p_end_block = ((aligned_t *) aBlock) + aSize;
aBlock -> p_next = NULL;
}
//=======================================================================
//function : ~NCollection_IncAllocator
//purpose : Destructor
//=======================================================================
NCollection_IncAllocator::~NCollection_IncAllocator ()
{
#ifdef DEB
if (IS_DEBUG)
Debug_Destroy(this);
#endif
Clean();
free (myFirstBlock);
}
//=======================================================================
//function : Allocate
//purpose : allocate a memory
//remark : returns NULL if allocation fails
//=======================================================================
void * NCollection_IncAllocator::Allocate (const size_t aSize)
{
aligned_t * aResult = NULL;
const size_t cSize = aSize ? IMEM_SIZE(aSize) : 0;
if (cSize > mySize) {
/* If the requested size exceeds normal allocation size, allocate
a separate block and place it as the head of the list */
aResult = (aligned_t *) allocateNewBlock (cSize+1);
if (aResult)
myFirstBlock -> p_free_space = myFirstBlock -> p_end_block;
} else
if (cSize <= IMEM_FREE(myFirstBlock)) {
/* If the requested size fits into the free space in the 1st block */
aResult = myFirstBlock -> allocateInBlock (cSize);
} else {
/* Search for a block in the list with enough free space */
int aMaxLookup = MaxLookup; /* limit the number of blocks to query */
IBlock * aCurrentBlock = myFirstBlock -> p_next;
while (aCurrentBlock && aMaxLookup--) {
if (cSize <= IMEM_FREE(aCurrentBlock)) {
aResult = aCurrentBlock -> allocateInBlock (cSize);
break;
}
aCurrentBlock = aCurrentBlock -> p_next;
}
if (aResult == NULL) {
/* There is no available block with enough free space. Create a new
one and place it in the head of the list */
aResult = (aligned_t *) allocateNewBlock (mySize);
if (aResult)
myFirstBlock -> p_free_space = aResult + cSize;
}
}
return aResult;
}
//=======================================================================
//function : Reallocate
//purpose :
//=======================================================================
void * NCollection_IncAllocator::Reallocate (void * theAddress,
const size_t oldSize,
const size_t newSize)
{
// Check that the dummy parameters are OK
if (theAddress == NULL || oldSize == 0)
return Allocate (newSize);
const size_t cOldSize = IMEM_SIZE(oldSize);
const size_t cNewSize = newSize ? IMEM_SIZE(newSize) : 0;
aligned_t * anAddress = (aligned_t *) theAddress;
// We check only the LAST allocation to do the real extension/contraction
if (anAddress + cOldSize == myFirstBlock -> p_free_space) {
myFirstBlock -> p_free_space = anAddress;
// If the new size fits into the memory block => OK
// This also includes any case of contraction
if (cNewSize <= IMEM_FREE(myFirstBlock)) {
myFirstBlock -> p_free_space += cNewSize;
return anAddress;
}
}
// In case of contraction of non-terminating allocation, do nothing
else if (cOldSize >= cNewSize)
return anAddress;
// Extension of non-terminated allocation if there is enough room in the
// current memory block
if (cNewSize <= IMEM_FREE(myFirstBlock)) {
aligned_t * aResult = myFirstBlock -> allocateInBlock (cNewSize);
if (aResult)
for (unsigned i = 0; i < cOldSize; i++)
aResult[i] = anAddress[i];
return aResult;
}
// This is either of the cases:
// - extension of non-terminating allocation, or
// - extension of terminating allocation when the new size is too big
// In both cases create a new memory block, allocate memory and copy there
// the reallocated memory.
aligned_t * aResult = (aligned_t *) allocateNewBlock (mySize);
if (aResult) {
myFirstBlock -> p_free_space = aResult + cNewSize;
for (unsigned i = 0; i < cOldSize; i++)
aResult[i] = anAddress[i];
}
return aResult;
}
//=======================================================================
//function : Free
//purpose :
//=======================================================================
void NCollection_IncAllocator::Free (void *)
{}
//=======================================================================
//function : Clean
//purpose :
//=======================================================================
void NCollection_IncAllocator::Clean ()
{
#ifdef ALLOC_TRACK_USAGE
printf ("\n..NCollection_IncAllocator: Memory size to clean:%8.1f kB (%x)\n",
double(GetMemSize())/1024, this);
#endif
IBlock * aBlock = myFirstBlock;
if (aBlock) {
aBlock -> p_free_space = (aligned_t *) &aBlock[1];
aBlock = aBlock -> p_next;
while (aBlock) {
IBlock * aNext = aBlock -> p_next;
free (aBlock);
aBlock = aNext;
}
myFirstBlock -> p_next = NULL;
}
myMemSize = 0;
}
//=======================================================================
//function : Reset
//purpose :
//=======================================================================
void NCollection_IncAllocator::Reset (const Standard_Boolean doReleaseMem)
{
if (doReleaseMem)
Clean();
else {
Standard_Integer aBlockCount(0);
IBlock * aBlock = myFirstBlock;
while (aBlock)
if (aBlockCount++ < MaxLookup) {
aBlock -> p_free_space = (aligned_t *) &aBlock[1];
if (aBlockCount < MaxLookup)
aBlock = aBlock -> p_next;
else {
IBlock * aNext = aBlock -> p_next;
aBlock -> p_next = NULL;
aBlock = aNext;
}
} else {
IBlock * aNext = aBlock -> p_next;
myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
free (aBlock);
aBlock = aNext;
}
}
}
//=======================================================================
//function : GetMemSize
//purpose : diagnostic utility
//=======================================================================
size_t NCollection_IncAllocator::GetMemSize () const
{
// size_t aResult = 0;
// IBlock * aBlock = myFirstBlock;
// while (aBlock) {
// aResult += (aBlock -> p_end_block - (aligned_t *) aBlock);
// aBlock = aBlock -> p_next;
// }
// return aResult * sizeof (aligned_t);
return myMemSize;
}
//=======================================================================
//function : allocateNewBlock
//purpose :
//=======================================================================
void * NCollection_IncAllocator::allocateNewBlock (const size_t cSize)
{
aligned_t * aResult = 0L;
const size_t aSz = cSize + IMEM_SIZE(sizeof(IBlock));
IBlock * aBlock = (IBlock *) malloc (aSz * sizeof(aligned_t));
if (aBlock) {
aBlock -> p_end_block = ((aligned_t *)aBlock) + aSz;
aBlock -> p_next = myFirstBlock;
myFirstBlock = aBlock;
aResult = (aligned_t *) IMEM_ALIGN(&aBlock[1]);
myMemSize += aSz * sizeof(aligned_t);
}
else
Standard_OutOfMemory::Raise("NCollection_IncAllocator: out of memory");
return aResult;
}