#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);
}