#include <NCollection_BaseAllocator.hxx>
#include <NCollection_DataMap.hxx>
+#include <NCollection_Map.hxx>
#include <NCollection_List.hxx>
#include <Standard_Mutex.hxx>
NCollection_BaseAllocator::CommonBaseAllocator();
//=======================================================================
-//function : StandardCallBack
-//purpose : Callback function to register alloc/free calls
+/**
+ * Structure for collecting statistics about blocks of one size
+ */
//=======================================================================
-
struct StorageInfo
{
Standard_Size roundSize;
: roundSize(theSize), nbAlloc(0), nbFree(0) {}
};
-static NCollection_DataMap<Standard_Size, StorageInfo> StorageMap;
+//=======================================================================
+/**
+ * Static data map (block_size -> StorageInfo)
+ */
+//=======================================================================
+static NCollection_DataMap<Standard_Size, StorageInfo>& StorageMap()
+{
+ static NCollection_IncAllocator TheAlloc;
+ static NCollection_DataMap<Standard_Size, StorageInfo>
+ TheMap (1, & TheAlloc);
+ return TheMap;
+}
+
+//=======================================================================
+/**
+ * Static data map (address -> AllocationID)
+ */
+//=======================================================================
+static NCollection_DataMap<Standard_Address, Standard_Size>& StorageIDMap()
+{
+ static NCollection_IncAllocator TheAlloc;
+ static NCollection_DataMap<Standard_Address, Standard_Size>
+ TheMap (1, & TheAlloc);
+ return TheMap;
+}
+
+//=======================================================================
+/**
+ * Static map (AllocationID)
+ */
+//=======================================================================
+static NCollection_Map<Standard_Size>& StorageIDSet()
+{
+ static NCollection_IncAllocator TheAlloc;
+ static NCollection_Map<Standard_Size> TheMap (1, & TheAlloc);
+ return TheMap;
+}
+
+//=======================================================================
+/**
+ * Exported value to set the block size for which it is required
+ * collecting alive allocation IDs.
+ * The method NCollection_BaseAllocator::PrintMemUsageStatistics
+ * dumps all alive IDs into the file alive.d in the current directory.
+ */
+//=======================================================================
+Standard_EXPORT Standard_Size& StandardCallBack_CatchSize()
+{
+ static Standard_Size Value = 0;
+ return Value;
+}
+
+//=======================================================================
+/**
+ * Exported value to set the allocation ID for which it is required
+ * to set a breakpoint on the moment of allocation or freeing.
+ * See the method NCollection_BaseAllocator::StandardCallBack
+ * where the value StandardCallBack_CatchID() is compared to the current ID.
+ * There you can place a break point at the stub assignment statement "a =".
+ */
+//=======================================================================
+Standard_EXPORT Standard_Size& StandardCallBack_CatchID()
+{
+ static Standard_Size Value = 0;
+ return Value;
+}
+
+//=======================================================================
+/**
+ * Static value of the current allocation ID. It provides unique
+ * numbering of allocation events.
+ */
+//=======================================================================
+static Standard_Size CurrentID = 0;
+
+//=======================================================================
+/**
+ * Exported function to reset the callback system to the initial state
+ */
+//=======================================================================
+Standard_EXPORT void StandardCallBack_Reset()
+{
+ StorageMap().Clear();
+ StorageIDMap().Clear();
+ StorageIDSet().Clear();
+ CurrentID = 0;
+ StandardCallBack_CatchSize() = 0;
+ StandardCallBack_CatchID() = 0;
+}
+
+//=======================================================================
+//function : StandardCallBack
+//purpose : Callback function to register alloc/free calls
+//=======================================================================
void NCollection_BaseAllocator::StandardCallBack
(const Standard_Boolean theIsAlloc,
- const Standard_Address /*theStorage*/,
+ const Standard_Address theStorage,
const Standard_Size theRoundSize,
const Standard_Size /*theSize*/)
{
- static int aLock = 0;
- if (aLock)
- return;
- aLock = 1;
- if (!StorageMap.IsBound(theRoundSize))
+ static Standard_Mutex aMutex;
+ Standard_Boolean isReentrant = Standard::IsReentrant();
+ if (isReentrant)
+ aMutex.Lock();
+ // statistics by storage size
+ NCollection_DataMap<Standard_Size, StorageInfo>& aStMap = StorageMap();
+ if (!aStMap.IsBound(theRoundSize))
{
StorageInfo aEmpty(theRoundSize);
- StorageMap.Bind(theRoundSize, aEmpty);
+ aStMap.Bind(theRoundSize, aEmpty);
}
- StorageInfo& aInfo = StorageMap(theRoundSize);
+ StorageInfo& aInfo = aStMap(theRoundSize);
if (theIsAlloc)
aInfo.nbAlloc++;
else
aInfo.nbFree++;
- aLock = 0;
+
+ if (theRoundSize == StandardCallBack_CatchSize())
+ {
+ // statistics by alive objects
+ NCollection_DataMap<Standard_Address, Standard_Size>& aStIDMap = StorageIDMap();
+ NCollection_Map<Standard_Size>& aStIDSet = StorageIDSet();
+ int a;
+ if (theIsAlloc)
+ {
+ aStIDMap.Bind(theStorage, ++CurrentID);
+ aStIDSet.Add(CurrentID);
+ if (CurrentID == StandardCallBack_CatchID())
+ {
+ // Place for break point for allocation of investigated ID
+ a = 1;
+ }
+ }
+ else
+ {
+ if (aStIDMap.IsBound(theStorage))
+ {
+ Standard_Size anID = aStIDMap(theStorage);
+ aStIDSet.Remove(anID);
+ if (anID == StandardCallBack_CatchID())
+ {
+ // Place for break point for freeing of investigated ID
+ a = 0;
+ }
+ }
+ }
+ }
+
+ if (isReentrant)
+ aMutex.Unlock();
}
//=======================================================================
// sort by roundsize
NCollection_List<StorageInfo> aColl;
NCollection_List<StorageInfo>::Iterator itLst;
- NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap);
+ NCollection_DataMap<Standard_Size, StorageInfo>::Iterator itMap(StorageMap());
for (; itMap.More(); itMap.Next())
{
for (itLst.Init(aColl); itLst.More(); itLst.Next())
Standard_Size aTotAlloc = 0;
Standard_Size aTotLeft = 0;
// print
- printf("%12s %12s %12s %12s %12s\n",
- "BlockSize", "NbAllocated", "NbLeft", "Allocated", "Left");
+ FILE * ff = fopen("memstat.d", "wt");
+ if (ff == NULL)
+ {
+ cout << "failure writing file memstat.d" << endl;
+ return;
+ }
+ fprintf(ff, "%12s %12s %12s %12s %12s\n",
+ "BlockSize", "NbAllocated", "NbLeft", "Allocated", "Left");
for (itLst.Init(aColl); itLst.More(); itLst.Next())
{
const StorageInfo& aInfo = itLst.Value();
Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.roundSize;
Standard_Size aSizeLeft = nbLeft * aInfo.roundSize;
- printf("%12d %12d %12d %12d %12d\n", aInfo.roundSize,
- aInfo.nbAlloc, nbLeft, aSizeAlloc, aSizeLeft);
+ fprintf(ff, "%12d %12d %12d %12d %12d\n", aInfo.roundSize,
+ aInfo.nbAlloc, nbLeft, aSizeAlloc, aSizeLeft);
aTotAlloc += aSizeAlloc;
aTotLeft += aSizeLeft;
}
- printf("%12s %12s %12s %12d %12d\n", "Total:", "", "",
- aTotAlloc, aTotLeft);
- fflush(stdout);
+ fprintf(ff, "%12s %12s %12s %12d %12d\n", "Total:", "", "",
+ aTotAlloc, aTotLeft);
+
+ if (!StorageIDSet().IsEmpty())
+ {
+ fprintf(ff, "Alive allocation numbers of size=%d\n", StandardCallBack_CatchSize());
+ NCollection_Map<Standard_Size>::Iterator itMap1(StorageIDSet());
+ for (; itMap1.More(); itMap1.Next())
+ fprintf(ff, "%d\n", itMap1.Key());
+ }
+ fclose(ff);
}
{
if (this == &theOther || theOther.IsEmpty())
return;
-
- theOther.myLast->Next() = myFirst;
+
+ if (IsEmpty())
+ myLast = theOther.myLast;
+ else
+ theOther.myLast->Next() = myFirst;
myFirst = theOther.myFirst;
theOther.myFirst = theOther.myLast = NULL;
void NCollection_BaseVector::Clear()
{
- for (Standard_Integer i = 0; i < myCapacity; i++)
- myData[i].Reinit (0, 0);
- myLength = 0;
- myNBlocks = 0;
+ if (myLength > 0) {
+ for (Standard_Integer i = 0; i < myCapacity; i++)
+ myData[i].Reinit (0, 0);
+ myLength = 0;
+ myNBlocks = 0;
+ }
}
//=======================================================================
for (Standard_Integer i = 0; i < myCapacity; i++)
myData[i].Reinit (0, 0);
myDataFree (* this, myData);
- myCapacity = myIncrement + myLength / myIncrement;
+ myCapacity = GetCapacity(myIncrement) + myLength / myIncrement;
myData = myDataInit (* this, myCapacity, NULL, 0);
// }
return * this;
myNBlocks + 1 + (theIndex - myLength) / myIncrement;
if (myCapacity < nNewBlock) {
// Reallocate the array myData
- do myCapacity += myIncrement; while (myCapacity <= nNewBlock);
+ do myCapacity += GetCapacity(myIncrement); while (myCapacity <= nNewBlock);
MemBlock * aNewData = myDataInit (* this, myCapacity, myData, myNBlocks);
myDataFree (* this, myData);
myData = aNewData;
#define NCollection_BaseVector_HeaderFile
#include <Standard_TypeDef.hxx>
+#include <NCollection_BaseAllocator.hxx>
#include <stddef.h>
#if !defined No_Exception && !defined No_Standard_OutOfRange
#pragma warning(disable:4355)
#endif
+// this value defines the number of blocks that are reserved
+// when the capacity of vector is increased
+inline Standard_Integer GetCapacity (const Standard_Integer theIncrement)
+{
+ return Max(theIncrement/8, 1);
+}
+
/**
* Class NCollection_BaseVector - base for generic vector
*/
// ------------ Class MemBlock ------------
class MemBlock {
protected:
- MemBlock ()
- : myFirstInd(0), myLength(0), mySize(0), myData(0L) {}
+ MemBlock (NCollection_BaseAllocator* theAlloc)
+ : myAlloc(theAlloc),
+ myFirstInd(0), myLength(0), mySize(0), myData(0L) {}
MemBlock (const Standard_Integer theFirstInd,
- const Standard_Integer theLength)
- : myFirstInd(theFirstInd), myLength(0), mySize(theLength), myData(0L) {}
- virtual ~MemBlock () {}
+ const Standard_Integer theLength,
+ NCollection_BaseAllocator* theAlloc)
+ : myAlloc(theAlloc),
+ myFirstInd(theFirstInd), myLength(0), mySize(theLength), myData(0L) {}
virtual void Reinit (const Standard_Integer,
const size_t) {}
Standard_Integer FirstIndex () const { return myFirstInd; }
size_t Size () const { return mySize; }
public:
+ virtual ~MemBlock () {}
void SetLength (const size_t theLen)
{ myLength = theLen; }
size_t Length () const { return myLength; }
Standard_Integer myFirstInd;
size_t myLength;
size_t mySize;
+ NCollection_BaseAllocator * myAlloc;
void * myData;
friend class NCollection_BaseVector;
};
NCollection_BaseVector (const size_t theSize,
const Standard_Integer theInc,
FuncPtrDataInit theDataInit,
- FuncPtrDataFree theDataFree)
+ FuncPtrDataFree theDataFree)
: myItemSize (theSize),
myIncrement (theInc),
myLength (0),
- myCapacity (theInc),
+ myCapacity (GetCapacity(myIncrement)),
myNBlocks (0),
myData (theDataInit (* this, myCapacity, NULL, 0)),
myDataInit (theDataInit),
//! Copy constructor
NCollection_BaseVector (const NCollection_BaseVector& theOther,
FuncPtrDataInit theDataInit,
- FuncPtrDataFree theDataFree)
+ FuncPtrDataFree theDataFree)
: myItemSize (theOther.myItemSize),
myIncrement (theOther.myIncrement),
myLength (theOther.Length()),
- myCapacity (theOther.myIncrement+theOther.Length()/theOther.myIncrement),
+ myCapacity (GetCapacity(myIncrement)+theOther.Length()/theOther.myIncrement),
myNBlocks (1 + (theOther.Length() - 1)/theOther.myIncrement),
myData (theDataInit (* this, myCapacity, NULL, 0)),
myDataInit (theDataInit),
// 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>
#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
{
#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]);
NCollection_IncAllocator::~NCollection_IncAllocator ()
{
+#ifdef DEB
+ if (IS_DEBUG)
+ Debug_Destroy(this);
+#endif
Clean();
free (myFirstBlock);
}
}
myFirstBlock -> p_next = NULL;
}
+ myMemSize = 0;
}
//=======================================================================
}
} else {
IBlock * aNext = aBlock -> p_next;
+ myMemSize -= (aBlock -> p_end_block - (aligned_t *) aBlock) * sizeof (aligned_t);
free (aBlock);
aBlock = aNext;
}
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);
+// 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;
}
//=======================================================================
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");
//! Free a previously allocated memory. Does nothing
Standard_EXPORT virtual void Free (void *anAddress);
- //! Diagnostic method, returns the number of bytes totally allocated
+ //! Diagnostic method, returns the total allocated size
Standard_EXPORT size_t GetMemSize () const;
//! Destructor (calls Clean() internally)
// --------- PROTECTED FIELDS ---------
IBlock * myFirstBlock;
size_t mySize;
+ size_t myMemSize;
public:
// Declaration of CASCADE RTTI
* return
* Number of objects accepted
*/
- Standard_Integer Select (Selector& theSelector) const
+ virtual Standard_Integer Select (Selector& theSelector) const
{ return (IsEmpty() ? 0 : Select (Root(), theSelector)); }
/**
\
_HUBTREE () : myTree(new UBTree) {} \
/* Empty constructor */ \
+ _HUBTREE (const Handle_NCollection_BaseAllocator& theAlloc) \
+ : myTree(new UBTree(theAlloc)) {} \
+ /* Constructor */ \
\
/* Access to the methods of UBTree */ \
\
: public NCollection_BaseCollection<TheItemType>,
public NCollection_BaseVector
{
- // **************** Implementation of the Iterator interface.
public:
+ typedef TheItemType TheItemTypeD;
// ----------------------------------------------------------------------
//! Nested class MemBlock
class MemBlock : public NCollection_BaseVector::MemBlock
public:
void * operator new (size_t, void * theAddress) { return theAddress; }
//! Empty constructor
- MemBlock () : NCollection_BaseVector::MemBlock(0,0) {}
+ MemBlock (NCollection_BaseAllocator* theAlloc)
+ : NCollection_BaseVector::MemBlock(0,0,theAlloc)
+ {}
//! Constructor
MemBlock (const Standard_Integer theFirstInd,
- const Standard_Integer theSize)
- : NCollection_BaseVector::MemBlock (theFirstInd, theSize)
- { myData = new TheItemType [theSize]; }
+ const Standard_Integer theSize,
+ NCollection_BaseAllocator* theAlloc)
+ : NCollection_BaseVector::MemBlock (theFirstInd, theSize, theAlloc)
+ {
+ myData = myAlloc->Allocate(theSize * sizeof(TheItemType));
+ for (size_t i=0; i < theSize; i++)
+ new (&((TheItemType *) myData)[i]) TheItemType;
+ }
//! Copy constructor
MemBlock (const MemBlock& theOther)
- : NCollection_BaseVector::MemBlock (theOther.FirstIndex(),theOther.Size())
+ : NCollection_BaseVector::MemBlock (theOther.FirstIndex(),theOther.Size(),
+ theOther.myAlloc)
{
myLength = theOther.Length();
- myData = new TheItemType [Size()];
- for (size_t i=0; i < Length(); i++)
- ((TheItemType *) myData)[i] = theOther.Value(i);
+ myData = myAlloc->Allocate(Size() * sizeof(TheItemType));
+ size_t i;
+ for (i=0; i < Length(); i++)
+ new (&((TheItemType *) myData)[i]) TheItemType(theOther.Value(i));
+ for (; i < Size(); i++)
+ new (&((TheItemType *) myData)[i]) TheItemType;
}
//! Reinit
virtual void Reinit (const Standard_Integer theFirst,
const size_t theSize)
{
- if (myData) delete [] (TheItemType *) myData;
- myData = (theSize > 0) ? new TheItemType [theSize] : NULL;
+ if (myData) {
+ for (size_t i=0; i < mySize; i++)
+ ((TheItemType *) myData)[i].~TheItemTypeD();
+ myAlloc->Free(myData);
+ myData = NULL;
+ }
+ if (theSize > 0) {
+ myData = myAlloc->Allocate(theSize * sizeof(TheItemType));
+ for (size_t i=0; i < theSize; i++)
+ new (&((TheItemType *) myData)[i]) TheItemType;
+ }
myFirstInd = theFirst;
mySize = theSize;
myLength = 0;
}
//! Destructor
- virtual ~MemBlock () { if (myData) delete [] (TheItemType *) myData; }
+ virtual ~MemBlock ()
+ {
+ if (myData) {
+ for (size_t i=0; i < Size(); i++)
+ ((TheItemType *) myData)[i].~TheItemTypeD();
+ myAlloc->Free(myData);
+ myData = NULL;
+ }
+ }
//! Operator () const
const TheItemType& Value (const Standard_Integer theIndex) const
{ return ((TheItemType *) myData) [theIndex]; }
i = aSize;
}
while (i < aCapacity)
- new (&aData[i++]) MemBlock;
+ new (&aData[i++]) MemBlock(aSelf.myAllocator.operator->());
return aData;
}