#endif
#include <Draw_Chronometer.hxx>
+#include <OSD_MAllocHook.hxx>
#if defined (__hpux) || defined ( HPUX )
#define RLIM_INFINITY 0x7fffffff
return 0;
}
+//=======================================================================
+//function : mallochook
+//purpose :
+//=======================================================================
+
+static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
+ const char** a)
+{
+ if (n < 2)
+ {
+ di << "\
+usage: mallochook cmd\n\
+where cmd is one of:\n\
+ set [<op>] - set callback to malloc/free; op is one of the following:\n\
+ 0 - set callback to NULL,\n\
+ 1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
+ 2 - set callback OSD_MAllocHook::LogFileHandler\n\
+ reset - reset the CollectBySize handler\n\
+ report1 [<outfile>]\n\
+ - write report from CollectBySize handler in <outfile>\n\
+ open [<logfile>]\n\
+ - open file for writing the log with LogFileHandler\n\
+ close - close the log file with LogFileHandler\n\
+ report2 [<flag>] [<logfile>] [<outfile>]\n\
+ - scan <logfile> written with LogFileHandler\n\
+ and make synthesized report in <outfile>; <flag> can be:\n\
+ 0 - simple stats by sizes (default),\n\
+ 1 - with alive allocation numbers\n\
+By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
+ << "\n";
+ return 0;
+ }
+ if (strcmp(a[1], "set") == 0)
+ {
+ int aType = (n > 2 ? atoi(a[2]) : 1);
+ if (aType < 0 || aType > 2)
+ {
+ di << "unknown op of the command set" << "\n";
+ return 1;
+ }
+ else if (aType == 0)
+ {
+ OSD_MAllocHook::SetCallback(NULL);
+ di << "callback is unset" << "\n";
+ }
+ else if (aType == 1)
+ {
+ OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
+ di << "callback is set to CollectBySize" << "\n";
+ }
+ else //if (aType == 2)
+ {
+ OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
+ di << "callback is set to LogFileHandler" << "\n";
+ }
+ }
+ else if (strcmp(a[1], "reset") == 0)
+ {
+ OSD_MAllocHook::GetCollectBySize()->Reset();
+ di << "CollectBySize handler is reset" << "\n";
+ }
+ else if (strcmp(a[1], "open") == 0)
+ {
+ const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
+ if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
+ {
+ di << "cannot create file " << aFileName << " for writing" << "\n";
+ return 1;
+ }
+ di << "log file " << aFileName << " is opened for writing" << "\n";
+ }
+ else if (strcmp(a[1], "close") == 0)
+ {
+ OSD_MAllocHook::GetLogFileHandler()->Close();
+ di << "log file is closed" << "\n";
+ }
+ else if (strcmp(a[1], "report1") == 0)
+ {
+ const char* aOutFile = "mem-stat.txt";
+ if (n > 2)
+ aOutFile = a[2];
+ if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
+ {
+ di << "report " << aOutFile << " has been created" << "\n";
+ }
+ else
+ {
+ di << "cannot create report " << aOutFile << "\n";
+ return 1;
+ }
+ }
+ else if (strcmp(a[1], "report2") == 0)
+ {
+ Standard_Boolean includeAlive = Standard_False;
+ const char* aLogFile = "mem-log.txt";
+ const char* aOutFile = "mem-stat.txt";
+ if (n > 2)
+ {
+ includeAlive = (atoi(a[2]) != 0);
+ if (n > 3)
+ {
+ aLogFile = a[3];
+ if (n > 4)
+ aOutFile = a[4];
+ }
+ }
+ if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
+ {
+ di << "report " << aOutFile << " has been created" << "\n";
+ }
+ else
+ {
+ di << "cannot create report " << aOutFile << " from the log file "
+ << aLogFile << "\n";
+ return 1;
+ }
+ }
+ else
+ {
+ di << "unrecognized command " << a[1] << "\n";
+ return 1;
+ }
+ return 0;
+}
+
void Draw::BasicCommands(Draw_Interpretor& theCommands)
{
__FILE__,chronom,g);
theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
__FILE__,dchronom,g);
+ theCommands.Add("mallochook",
+ "debug memory allocation/deallocation, w/o args for help",
+ __FILE__, mallochook, g);
}
--- /dev/null
+// File: OSD_MAllocHook.cxx
+// Created: 04.02.2011
+// Author: Mikhail SAZONOV
+// Copyright: Open CASCADE S.A.S. 2011
+
+#include <OSD_MAllocHook.hxx>
+
+#ifndef WNT
+#if !defined __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS
+#endif
+#include <stdint.h>
+#endif
+
+#include <set>
+#include <map>
+
+#define MAX_STR 80
+
+static OSD_MAllocHook::Callback* MypCurrentCallback = NULL;
+
+//=======================================================================
+//function : GetCallback
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::Callback* OSD_MAllocHook::GetCallback()
+{
+ return MypCurrentCallback;
+}
+
+//=======================================================================
+//function : GetLogFileHandler
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::LogFileHandler* OSD_MAllocHook::GetLogFileHandler()
+{
+ static LogFileHandler MyHandler;
+ return &MyHandler;
+}
+
+//=======================================================================
+//function : GetCollectBySize
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::CollectBySize* OSD_MAllocHook::GetCollectBySize()
+{
+ static CollectBySize MyHandler;
+ return &MyHandler;
+}
+
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Platform-dependent methods
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+#ifdef WNT
+#include <crtdbg.h>
+
+static long getRequestNum(void* pvData, long lRequest, size_t& theSize)
+{
+ if (_CrtIsValidHeapPointer(pvData))
+ {
+#if _MSC_VER == 1500 // VS 2008
+#define nNoMansLandSize 4
+ // the header struct is taken from crt/src/dbgint.h
+ struct _CrtMemBlockHeader
+ {
+#ifdef _WIN64
+ int nBlockUse;
+ size_t nDataSize;
+#else
+ size_t nDataSize;
+ int nBlockUse;
+#endif
+ long lRequest;
+ unsigned char gap[nNoMansLandSize];
+ };
+ _CrtMemBlockHeader* aHeader = ((_CrtMemBlockHeader*)pvData)-1;
+ theSize = aHeader->nDataSize;
+ return aHeader->lRequest;
+#endif
+ }
+ return lRequest;
+}
+
+int __cdecl MyAllocHook(int nAllocType,
+ void * pvData,
+ size_t nSize,
+ int nBlockUse,
+ long lRequest,
+ const unsigned char * /*szFileName*/,
+ int /*nLine*/)
+{
+ if (nBlockUse == _CRT_BLOCK || // Ignore internal C runtime library allocations
+ MypCurrentCallback == NULL)
+ return(1);
+
+ if (nAllocType == _HOOK_ALLOC)
+ MypCurrentCallback->AllocEvent(nSize, lRequest);
+ else if (nAllocType == _HOOK_FREE)
+ {
+ // for free hook, lRequest is not defined,
+ // but we can take it from the CRT mem block header
+ size_t aSize = 0;
+ lRequest = getRequestNum(pvData, lRequest, aSize);
+ MypCurrentCallback->FreeEvent(pvData, aSize, lRequest);
+ }
+ else // _HOOK_REALLOC
+ {
+ // for realloc hook, lRequest shows the new request,
+ // and we should get request number for old block
+ size_t anOldSize = 0;
+ long anOldRequest = getRequestNum(pvData, 0, anOldSize);
+ MypCurrentCallback->FreeEvent(pvData, anOldSize, anOldRequest);
+ MypCurrentCallback->AllocEvent(nSize, lRequest);
+ }
+
+ return(1); // Allow the memory operation to proceed
+}
+
+//=======================================================================
+//function : SetCallback
+//purpose :
+//=======================================================================
+
+void OSD_MAllocHook::SetCallback(Callback* theCB)
+{
+ MypCurrentCallback = theCB;
+ if (theCB == NULL)
+ _CrtSetAllocHook(NULL);
+ else
+ _CrtSetAllocHook(MyAllocHook);
+}
+
+#else // ! WNT
+
+// Not yet implemented for non-WNT platform
+
+void OSD_MAllocHook::SetCallback(Callback* theCB)
+{
+ MypCurrentCallback = theCB;
+}
+
+#endif // WNT
+
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// LogFileHandler handler methods
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+//=======================================================================
+//function : LogFileHandler::LogFileHandler
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::LogFileHandler::LogFileHandler()
+: myLogFile(NULL),
+ myBreakSize(0)
+{
+}
+
+//=======================================================================
+//function : LogFileHandler::~LogFileHandler
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::LogFileHandler::~LogFileHandler()
+{
+ Close();
+}
+
+//=======================================================================
+//function : LogFileHandler::Open
+//purpose :
+//=======================================================================
+
+Standard_Boolean OSD_MAllocHook::LogFileHandler::Open(const char* theFileName)
+{
+ Close();
+ myLogFile = fopen(theFileName, "w");
+ if (myLogFile != NULL)
+ {
+ fputs("Operation type; Request Number; Block Size\n", myLogFile);
+ fputs("------------------------------------------\n", myLogFile);
+ }
+ return myLogFile != NULL;
+}
+
+//=======================================================================
+//function : LogFileHandler::Close
+//purpose :
+//=======================================================================
+
+void OSD_MAllocHook::LogFileHandler::Close()
+{
+ if (myLogFile != NULL)
+ {
+ fclose(myLogFile);
+ myLogFile = NULL;
+ }
+}
+
+//=======================================================================
+//function : LogFileHandler::MakeReport
+//purpose :
+//=======================================================================
+
+struct StorageInfo
+{
+ Standard_Size size;
+ int nbAlloc;
+ int nbFree;
+ int nbLeftPeak;
+ std::set<unsigned long>* alive;
+ StorageInfo()
+ : size(0), nbAlloc(0), nbFree(0), nbLeftPeak(0), alive(NULL) {}
+ StorageInfo(Standard_Size theSize)
+ : size(theSize), nbAlloc(0), nbFree(0), nbLeftPeak(0), alive(NULL) {}
+ ~StorageInfo()
+ {
+ if (alive)
+ delete alive;
+ }
+ std::set<unsigned long>& Alive()
+ {
+ if (!alive)
+ alive = new std::set<unsigned long>;
+ return *alive;
+ }
+ const std::set<unsigned long>& Alive() const
+ {
+ return *alive;
+ }
+};
+
+inline bool operator < (const StorageInfo& one, const StorageInfo& two)
+{
+ return one.size < two.size;
+}
+
+Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport
+ (const char* theLogFile,
+ const char* theOutFile,
+ const Standard_Boolean theIncludeAlive)
+{
+ // open log file
+ FILE* aLogFile = fopen(theLogFile, "r");
+ if (aLogFile == NULL)
+ return Standard_False;
+
+ // skip 2 header lines
+ char aStr[MAX_STR];
+ if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
+ {
+ fclose(aLogFile);
+ return Standard_False;
+ }
+ if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
+ {
+ fclose(aLogFile);
+ return Standard_False;
+ }
+
+ // scan the log file
+ size_t aTotalLeftSize = 0;
+ size_t aTotalPeakSize = 0;
+ std::set<StorageInfo> aStMap;
+ while (fgets(aStr, MAX_STR-1, aLogFile) != NULL)
+ {
+ // detect operation type, request number and block size
+ unsigned long aReqNum, aSize;
+ char* aType = aStr;
+ char* pStr = aStr;
+ //sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
+ while (*pStr != ' ' && *pStr) pStr++;
+ *pStr++ = '\0';
+ while (*pStr == ' ' && *pStr) pStr++;
+ aReqNum = atol(pStr);
+ while (*pStr != ' ' && *pStr) pStr++;
+ while (*pStr == ' ' && *pStr) pStr++;
+ aSize = atol(pStr);
+ Standard_Boolean isAlloc = Standard_False;
+ if (strcmp(aType, "alloc") == 0)
+ {
+ isAlloc = Standard_True;
+ }
+ else if (strcmp(aType, "free") != 0)
+ continue;
+
+ // collect statistics by storage size
+ StorageInfo aSuchInfo(aSize);
+ std::set<StorageInfo>::iterator aFound = aStMap.find(aSuchInfo);
+ if (aFound == aStMap.end())
+ aFound = aStMap.insert(aSuchInfo).first;
+ StorageInfo& aInfo = const_cast<StorageInfo&>(*aFound);
+ if (isAlloc)
+ {
+ if (aInfo.nbAlloc + 1 > 0)
+ aInfo.nbAlloc++;
+ aTotalLeftSize += aSize;
+ if (aTotalLeftSize > aTotalPeakSize)
+ aTotalPeakSize = aTotalLeftSize;
+ int nbLeft = aInfo.nbAlloc - aInfo.nbFree;
+ if (nbLeft > aInfo.nbLeftPeak)
+ aInfo.nbLeftPeak = nbLeft;
+ aInfo.Alive().insert(aReqNum);
+ }
+ else
+ {
+ std::set<unsigned long>::iterator aFoundReqNum =
+ aInfo.Alive().find(aReqNum);
+ if (aFoundReqNum == aInfo.Alive().end())
+ // freeing non-registered block, skip it
+ continue;
+ aTotalLeftSize -= aSize;
+ aInfo.Alive().erase(aFoundReqNum);
+ if (aInfo.nbAlloc + 1 > 0)
+ aInfo.nbFree++;
+ }
+ }
+ fclose(aLogFile);
+
+ // print the report
+ FILE* aRepFile = fopen(theOutFile, "w");
+ if (aRepFile == NULL)
+ return Standard_False;
+ fprintf(aRepFile, "%10s %10s %10s %10s %10s %10s %10s\n",
+ "BlockSize", "NbAlloc", "NbLeft", "NbLeftPeak",
+ "AllocSize", "LeftSize", "PeakSize");
+ Standard_Size aTotAlloc = 0;
+ for (std::set<StorageInfo>::const_iterator it = aStMap.begin();
+ it != aStMap.end(); ++it)
+ {
+ const StorageInfo& aInfo = *it;
+ Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
+ Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.size;
+ Standard_Size aSizeLeft = nbLeft * aInfo.size;
+ Standard_Size aSizePeak = aInfo.nbLeftPeak * aInfo.size;
+ fprintf(aRepFile, "%10d %10d %10d %10d %10Iu %10Iu %10Iu\n", aInfo.size,
+ aInfo.nbAlloc, nbLeft, aInfo.nbLeftPeak,
+ aSizeAlloc, aSizeLeft, aSizePeak);
+ if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
+ aTotAlloc = SIZE_MAX;
+ else
+ aTotAlloc += aSizeAlloc;
+ if (theIncludeAlive && !aInfo.Alive().empty())
+ {
+ for (std::set<unsigned long>::const_iterator it1 = aInfo.alive->begin();
+ it1 != aInfo.alive->end(); ++it1)
+ fprintf(aRepFile, "%10lu\n", *it1);
+ }
+ }
+ fprintf(aRepFile, "%10s %10s %10s %10s%c%10Iu %10Iu %10Iu\n", "Total:",
+ "", "", "", (aTotAlloc == SIZE_MAX ? '>' : ' '), aTotAlloc,
+ aTotalLeftSize, aTotalPeakSize);
+ fclose(aRepFile);
+ return Standard_True;
+}
+
+//=======================================================================
+//function : LogFileHandler::AllocEvent
+//purpose :
+//=======================================================================
+
+void OSD_MAllocHook::LogFileHandler::AllocEvent
+ (size_t theSize,
+ long theRequestNum)
+{
+ if (myLogFile != NULL)
+ {
+ myMutex.Lock();
+ fprintf(myLogFile, "alloc %10lu %10u\n", theRequestNum, theSize);
+ myMutex.Unlock();
+ if (myBreakSize == theSize)
+ {
+ int a = 1;
+ }
+ }
+}
+
+//=======================================================================
+//function : LogFileHandler::FreeEvent
+//purpose :
+//=======================================================================
+
+void OSD_MAllocHook::LogFileHandler::FreeEvent
+ (void* /*theData*/,
+ size_t theSize,
+ long theRequestNum)
+{
+ if (myLogFile != NULL)
+ {
+ myMutex.Lock();
+ fprintf(myLogFile, "free %10lu %10u\n", theRequestNum, theSize);
+ myMutex.Unlock();
+ }
+}
+
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// CollectBySize handler methods
+//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+//=======================================================================
+//function : CollectBySize::CollectBySize
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::CollectBySize::CollectBySize()
+: myArray(NULL),
+ myTotalLeftSize(0),
+ myTotalPeakSize(0),
+ myBreakSize(0)
+{
+ Reset();
+}
+
+//=======================================================================
+//function : CollectBySize::~CollectBySize
+//purpose :
+//=======================================================================
+
+OSD_MAllocHook::CollectBySize::~CollectBySize()
+{
+ if (myArray != NULL)
+ delete [] myArray;
+}
+
+//=======================================================================
+//function : CollectBySize::Reset
+//purpose :
+//=======================================================================
+
+#define MAX_ALLOC_SIZE 2000000u
+
+void OSD_MAllocHook::CollectBySize::Reset()
+{
+ myMutex.Lock();
+ if (myArray == NULL)
+ myArray = new Numbers[MAX_ALLOC_SIZE];
+ else
+ {
+ for (int i = 0; i < MAX_ALLOC_SIZE; i++)
+ myArray[i] = Numbers();
+ }
+ myTotalLeftSize = 0;
+ myTotalPeakSize = 0;
+ myMutex.Unlock();
+}
+
+//=======================================================================
+//function : CollectBySize::MakeReport
+//purpose :
+//=======================================================================
+
+Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
+{
+ // print the report
+ FILE* aRepFile = fopen(theOutFile, "w");
+ if (aRepFile == NULL)
+ return Standard_False;
+ fprintf(aRepFile, "%10s %10s %10s %10s %10s %10s %10s\n",
+ "BlockSize", "NbAlloc", "NbLeft", "NbLeftPeak",
+ "AllocSize", "LeftSize", "PeakSize");
+ Standard_Size aTotAlloc = 0;
+ for (int i = 0; i < MAX_ALLOC_SIZE; i++)
+ {
+ if (myArray[i].nbAlloc > 0)
+ {
+ Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
+ if (nbLeft < 0)
+ nbLeft = 0;
+ int aSize = i + 1;
+ Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
+ Standard_Size aSizeLeft = nbLeft * aSize;
+ Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
+ fprintf(aRepFile, "%10d %10d %10d %10d %10Iu %10Iu %10Iu\n", aSize,
+ myArray[i].nbAlloc, nbLeft, myArray[i].nbLeftPeak,
+ aSizeAlloc, aSizeLeft, aSizePeak);
+ if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
+ aTotAlloc = SIZE_MAX;
+ else
+ aTotAlloc += aSizeAlloc;
+ }
+ }
+ fprintf(aRepFile, "%10s %10s %10s %10s%c%10Iu %10Iu %10Iu\n", "Total:",
+ "", "", "", (aTotAlloc == SIZE_MAX ? '>' : ' '), aTotAlloc,
+ myTotalLeftSize, myTotalPeakSize);
+ fclose(aRepFile);
+ return Standard_True;
+}
+
+//=======================================================================
+//function : CollectBySize::AllocEvent
+//purpose :
+//=======================================================================
+
+void OSD_MAllocHook::CollectBySize::AllocEvent
+ (size_t theSize,
+ long /*theRequestNum*/)
+{
+ if (myBreakSize == theSize)
+ {
+ int a = 1;
+ }
+ if (theSize > 0)
+ {
+ myMutex.Lock();
+ int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
+ if (myArray[ind].nbAlloc + 1 > 0)
+ myArray[ind].nbAlloc++;
+ myTotalLeftSize += theSize;
+ int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
+ if (nbLeft > myArray[ind].nbLeftPeak)
+ myArray[ind].nbLeftPeak = nbLeft;
+ if (myTotalLeftSize > myTotalPeakSize)
+ myTotalPeakSize = myTotalLeftSize;
+ myMutex.Unlock();
+ }
+}
+
+//=======================================================================
+//function : CollectBySize::FreeEvent
+//purpose :
+//=======================================================================
+
+void OSD_MAllocHook::CollectBySize::FreeEvent
+ (void* /*theData*/,
+ size_t theSize,
+ long /*theRequestNum*/)
+{
+ if (theSize > 0 && myTotalLeftSize >= theSize)
+ {
+ myMutex.Lock();
+ int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
+ if (myArray[ind].nbFree + 1 > 0)
+ myArray[ind].nbFree++;
+ myTotalLeftSize -= theSize;
+ myMutex.Unlock();
+ }
+}
--- /dev/null
+// File: OSD_MAllocHook.hxx
+// Created: 03.02.2011
+// Author: Mikhail SAZONOV
+// Copyright: Open CASCADE S.A.S. 2011
+
+#ifndef _OSD_MAllocHook_HeaderFile
+#define _OSD_MAllocHook_HeaderFile
+
+#include <Standard_TypeDef.hxx>
+#include <Standard_Mutex.hxx>
+#include <stdio.h>
+
+/**
+ * This class provides the possibility to set callback for memory
+ * allocation/deallocation.
+ * On MS Windows, it works only in Debug builds. It relies on the
+ * debug CRT function _CrtSetAllocHook (see MSDN for help).
+ */
+class OSD_MAllocHook
+{
+public:
+ /**
+ * Interface of a class that should handle allocation/deallocation events
+ */
+ class Callback
+ {
+ public:
+ //! Allocation event handler
+ /**
+ * It is called when allocation is done
+ * @param theSize
+ * the size of the memory block in bytes
+ * @param theRequestNum
+ * the allocation order number of the memory block
+ */
+ virtual void AllocEvent
+ (size_t theSize,
+ long theRequestNum) = 0;
+
+ //! Freeing event handler
+ /**
+ * It is called when the block is freed
+ * @param theData
+ * the pointer to the user data section of the memory block
+ * @param theSize
+ * the size of the memory block in bytes
+ * @param theRequestNum
+ * the allocation order number of the memory block
+ */
+ virtual void FreeEvent
+ (void* theData,
+ size_t theSize,
+ long theRequestNum) = 0;
+ };
+
+ /**
+ * Implementation of the handler that collects all events
+ * to the log file. It contains the method to generate the report
+ * from the log file.
+ */
+ class LogFileHandler: public Callback
+ {
+ public:
+ //! Constructor
+ Standard_EXPORT LogFileHandler();
+
+ //! Destructor
+ Standard_EXPORT ~LogFileHandler();
+
+ //! Create the file and start collecting events.
+ //! Return false if the file with the given name cannot be created.
+ Standard_EXPORT Standard_Boolean Open(const char* theFileName);
+
+ //! Close the file and stop collecting events
+ Standard_EXPORT void Close();
+
+ //! Make synthesized report on the given log file.
+ /**
+ * Generate an easy to use report in the
+ * new file with the given name, taking the given log file as input.
+ * If theIncludeAlive is true then
+ * include into the report the alive allocation numbers.
+ */
+ Standard_EXPORT static Standard_Boolean MakeReport
+ (const char* theLogFile,
+ const char* theOutFile,
+ const Standard_Boolean theIncludeAlive = Standard_False);
+
+ Standard_EXPORT virtual void AllocEvent(size_t, long);
+ Standard_EXPORT virtual void FreeEvent(void*, size_t, long);
+
+ private:
+ FILE* myLogFile;
+ Standard_Mutex myMutex;
+ size_t myBreakSize;
+ };
+
+ /**
+ * Implementation of the handler that collects numbers of
+ * allocations/deallocations for each block size directly in the memory.
+ */
+ class CollectBySize: public Callback
+ {
+ public:
+ //! Constructor
+ Standard_EXPORT CollectBySize();
+
+ //! Destructor
+ Standard_EXPORT ~CollectBySize();
+
+ //! Reset the buffer and start collecting events.
+ Standard_EXPORT void Reset();
+
+ //! Write report in the given file.
+ Standard_EXPORT Standard_Boolean MakeReport(const char* theOutFile);
+
+ Standard_EXPORT virtual void AllocEvent(size_t, long);
+ Standard_EXPORT virtual void FreeEvent(void*, size_t, long);
+
+ private:
+ struct Numbers
+ {
+ int nbAlloc;
+ int nbFree;
+ int nbLeftPeak;
+ Numbers() : nbAlloc(0), nbFree(0), nbLeftPeak(0) {}
+ };
+
+ Standard_Mutex myMutex;
+ Numbers* myArray;
+ size_t myTotalLeftSize;
+ size_t myTotalPeakSize;
+ size_t myBreakSize;
+ };
+
+ //! Set handler of allocation/deallocation events
+ /**
+ * You can pass here any implementation. For easy start, you can try
+ * with the predefined handler LogFileHandler, which static instance
+ * is returned by GetLogFileHandler().
+ * To clear the handler, pass NULL here.
+ */
+ Standard_EXPORT static void SetCallback
+ (Callback* theCB);
+
+ //! Get current handler of allocation/deallocation events
+ Standard_EXPORT static Callback* GetCallback();
+
+ //! Get static instance of LogFileHandler handler
+ Standard_EXPORT static LogFileHandler* GetLogFileHandler();
+
+ //! Get static instance of CollectBySize handler
+ Standard_EXPORT static CollectBySize* GetCollectBySize();
+};
+
+#endif /* _OSD_MAllocHook_HeaderFile */