#include <OSD_Chronometer.hxx>
#include <OSD_Environment.hxx>
#include <OSD_Exception_CTRL_BREAK.hxx>
-#include <OSD_MAllocHook.hxx>
#include <OSD_MemInfo.hxx>
#include <OSD_Parallel.hxx>
#include <OSD_PerfMeter.hxx>
//=================================================================================================
-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 ? Draw::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 = (Draw::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;
-}
-
-//=================================================================================================
-
static int dlocale(Draw_Interpretor& di, Standard_Integer n, const char** argv)
{
int category = LC_ALL;
"\n\t\t: chrono t -stop -show";
theCommands.Add("chrono", aChronoHelp, __FILE__, dchronom, g);
theCommands.Add("dchrono", aChronoHelp, __FILE__, dchronom, g);
- theCommands.Add("mallochook",
- "debug memory allocation/deallocation, w/o args for help",
- __FILE__,
- mallochook,
- g);
theCommands.Add("meminfo",
"meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
" : memory counters for this process",
+++ /dev/null
-// Created on: 2011-02-04
-// Created by: Mikhail SAZONOV
-// Copyright (c) 2011-2014 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-#include <OSD_MAllocHook.hxx>
-
-#ifndef _MSC_VER
- #if !defined __STDC_LIMIT_MACROS
- #define __STDC_LIMIT_MACROS
- #endif
- #include <stdint.h>
-#endif
-
-#include <set>
-#include <map>
-#include <cstdlib>
-#include <cstring>
-#include <iomanip>
-
-#ifndef SIZE_MAX
- #define SIZE_MAX UINT_MAX
-#endif
-
-#define MAX_STR 80
-
-static OSD_MAllocHook::Callback* MypCurrentCallback = NULL;
-
-namespace
-{
-// dummy function to call at place where break point might be needed
-static unsigned debug_counter = 0;
-
-inline void place_for_breakpoint()
-{
- // this statement is just to have any instruction in object code,
- // otherwise compiler does not leave a place for break point
- debug_counter++;
-}
-} // namespace
-
-//=================================================================================================
-
-OSD_MAllocHook::Callback* OSD_MAllocHook::GetCallback()
-{
- return MypCurrentCallback;
-}
-
-//=================================================================================================
-
-OSD_MAllocHook::LogFileHandler* OSD_MAllocHook::GetLogFileHandler()
-{
- static LogFileHandler MyHandler;
- return &MyHandler;
-}
-
-//=================================================================================================
-
-OSD_MAllocHook::CollectBySize* OSD_MAllocHook::GetCollectBySize()
-{
- static CollectBySize MyHandler;
- return &MyHandler;
-}
-
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// Platform-dependent methods
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-#ifdef _MSC_VER
- #include <crtdbg.h>
-
- #if _MSC_VER >= 1500 /* VS 2008 */
-
-static long getRequestNum(void* pvData, long lRequest, size_t& theSize)
-{
- #ifdef _DEBUG /* protect against invalid pointer; in Release, _CrtIsValidHeapPointer is always \
- 1 */
- if (!_CrtIsValidHeapPointer(pvData))
- return lRequest;
- #else
- (void)lRequest; // avoid compiler warning on unused arg
- #endif
-
- #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;
-}
-
- #else /* _MSC_VER < 1500 */
-
-static long getRequestNum(void* /*pvData*/, long lRequest, size_t& /*theSize*/)
-{
- return lRequest;
-}
-
- #endif /* _MSC_VER == 1500 */
-
-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
-}
-
-//=================================================================================================
-
-void OSD_MAllocHook::SetCallback(Callback* theCB)
-{
- MypCurrentCallback = theCB;
- if (theCB == NULL)
- _CrtSetAllocHook(NULL);
- else
- _CrtSetAllocHook(MyAllocHook);
-}
-
-#else // ! _MSC_VER
-
-// Not yet implemented for non-WNT platform
-
-void OSD_MAllocHook::SetCallback(Callback* theCB)
-{
- MypCurrentCallback = theCB;
-}
-
-#endif // _MSC_VER
-
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// LogFileHandler handler methods
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-//=================================================================================================
-
-OSD_MAllocHook::LogFileHandler::LogFileHandler()
- : myBreakSize(0)
-{
- myLogFile.imbue(std::locale("C"));
-}
-
-//=================================================================================================
-
-OSD_MAllocHook::LogFileHandler::~LogFileHandler()
-{
- Close();
-}
-
-//=================================================================================================
-
-Standard_Boolean OSD_MAllocHook::LogFileHandler::Open(const char* theFileName)
-{
- Close();
- myLogFile.open(theFileName);
- if (!myLogFile.is_open())
- {
- return Standard_False;
- }
-
- myLogFile << "Operation type; Request Number; Block Size\n"
- "------------------------------------------\n";
- return Standard_True;
-}
-
-//=================================================================================================
-
-void OSD_MAllocHook::LogFileHandler::Close()
-{
- if (myLogFile.is_open())
- {
- myLogFile.close();
- }
-}
-
-//=================================================================================================
-
-namespace
-{
-struct StorageInfo
-{
- Standard_Size size;
- Standard_Integer nbAlloc;
- Standard_Integer nbFree;
- Standard_Integer nbLeftPeak;
- std::set<unsigned long> alive;
-
- StorageInfo(Standard_Size theSize = 0)
- : size(theSize),
- nbAlloc(0),
- nbFree(0),
- nbLeftPeak(0),
- alive()
- {
- }
-
- bool operator<(const StorageInfo& theOther) const { return size < theOther.size; }
-};
-} // namespace
-
-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
- std::ofstream aRepFile(theOutFile);
- if (!aRepFile.is_open())
- {
- return Standard_False;
- }
- aRepFile.imbue(std::locale("C"));
-
- aRepFile << std::setw(20) << "BlockSize " << std::setw(10) << "NbAlloc " << std::setw(10)
- << "NbLeft " << std::setw(10) << "NbLeftPeak " << std::setw(20) << "AllocSize "
- << std::setw(20) << "LeftSize " << std::setw(20) << "PeakSize " << std::endl;
-
- 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;
-
- aRepFile << std::setw(20) << aInfo.size << ' ' << std::setw(10) << aInfo.nbAlloc << ' '
- << std::setw(10) << nbLeft << ' ' << std::setw(10) << aInfo.nbLeftPeak << ' '
- << std::setw(20) << aSizeAlloc << ' ' << std::setw(20) << aSizeLeft << ' '
- << std::setw(20) << aSizePeak << std::endl;
-
- 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)
- aRepFile << std::setw(10) << *it1;
- }
- }
- aRepFile << std::setw(20) << "Total:" << std::setw(10) << "" << ' ' << std::setw(10) << "" << ' '
- << std::setw(10) << "" << ' ' << (aTotAlloc == SIZE_MAX ? '>' : ' ') << std::setw(20)
- << aTotAlloc << ' ' << std::setw(20) << aTotalLeftSize << ' ' << std::setw(20)
- << aTotalPeakSize << std::endl;
-
- aRepFile.close();
- return Standard_True;
-}
-
-//=================================================================================================
-
-void OSD_MAllocHook::LogFileHandler::AllocEvent(size_t theSize, long theRequestNum)
-{
- if (myLogFile.is_open())
- {
- myMutex.Lock();
- myLogFile << "alloc " << std::setw(10) << theRequestNum << std::setw(20) << theSize
- << std::endl;
- if (myBreakSize == theSize)
- place_for_breakpoint();
- myMutex.Unlock();
- }
-}
-
-//=================================================================================================
-
-void OSD_MAllocHook::LogFileHandler::FreeEvent(void* /*theData*/,
- size_t theSize,
- long theRequestNum)
-{
- if (myLogFile.is_open())
- {
- myMutex.Lock();
- myLogFile << "free " << std::setw(20) << theRequestNum << std::setw(20) << theSize << std::endl;
- myMutex.Unlock();
- }
-}
-
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// CollectBySize handler methods
-//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-//=================================================================================================
-
-OSD_MAllocHook::CollectBySize::CollectBySize()
- : myArray(NULL),
- myTotalLeftSize(0),
- myTotalPeakSize(0),
- myBreakSize(0),
- myBreakPeak(0)
-{
- Reset();
-}
-
-//=================================================================================================
-
-OSD_MAllocHook::CollectBySize::~CollectBySize()
-{
- if (myArray != NULL)
- delete[] myArray;
-}
-
-//=================================================================================================
-
-#define MAX_ALLOC_SIZE 2000000
-const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
-
-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();
-}
-
-//=================================================================================================
-
-Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
-{
- // print the report
- std::ofstream aRepFile(theOutFile);
- if (!aRepFile.is_open())
- return Standard_False;
- std::locale aCLoc("C");
- aRepFile.imbue(aCLoc);
-
- aRepFile << std::setw(10) << "BlockSize " << std::setw(10) << "NbAlloc " << std::setw(10)
- << "NbLeft " << std::setw(10) << "NbLeftPeak " << std::setw(20) << "AllocSize "
- << std::setw(20) << "LeftSize " << std::setw(20) << "PeakSize " << std::endl;
-
- Standard_Size aTotAlloc = 0;
- for (int i = 0; i < MAX_ALLOC_SIZE; i++)
- {
- if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
- {
- Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
- int aSize = i + 1;
- Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
- ptrdiff_t aSizeLeft = nbLeft * aSize;
- Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
-
- aRepFile << std::setw(10) << aSize << ' ' << std::setw(10) << myArray[i].nbAlloc << ' '
- << std::setw(10) << nbLeft << ' ' << std::setw(10) << myArray[i].nbLeftPeak << ' '
- << std::setw(20) << aSizeAlloc << ' ' << std::setw(20) << aSizeLeft << ' '
- << std::setw(20) << aSizePeak << std::endl;
-
- if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
- aTotAlloc = SIZE_MAX;
- else
- aTotAlloc += aSizeAlloc;
- }
- }
- aRepFile << std::setw(10) << "Total:" << ' ' << std::setw(10) << "" << ' ' << std::setw(10) << ""
- << ' ' << std::setw(10) << "" << ' ' << (aTotAlloc == SIZE_MAX ? '>' : ' ')
- << std::setw(20) << aTotAlloc << ' ' << std::setw(20) << myTotalLeftSize << ' '
- << std::setw(20) << myTotalPeakSize << std::endl;
- aRepFile.close();
- return Standard_True;
-}
-
-//=================================================================================================
-
-void OSD_MAllocHook::CollectBySize::AllocEvent(size_t theSize, long /*theRequestNum*/)
-{
- if (myBreakSize == theSize)
- place_for_breakpoint();
- if (theSize > 0)
- {
- myMutex.Lock();
- int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE - 1 : (int)(theSize - 1));
- myArray[ind].nbAlloc++;
- myTotalLeftSize += theSize;
- int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
- if (nbLeft > myArray[ind].nbLeftPeak)
- {
- myArray[ind].nbLeftPeak = nbLeft;
- if (myBreakPeak != 0 && (myBreakSize == theSize || myBreakSize == 0))
- {
- const Standard_Size aSizePeak = myArray[ind].nbLeftPeak * theSize;
- if (aSizePeak > myBreakPeak)
- {
- place_for_breakpoint();
- }
- }
- }
- if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
- myTotalPeakSize = myTotalLeftSize;
- myMutex.Unlock();
- }
-}
-
-//=================================================================================================
-
-void OSD_MAllocHook::CollectBySize::FreeEvent(void* /*theData*/,
- size_t theSize,
- long /*theRequestNum*/)
-{
- if (theSize > 0)
- {
- myMutex.Lock();
- int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE - 1 : (int)(theSize - 1));
- myArray[ind].nbFree++;
- myTotalLeftSize -= theSize;
- myMutex.Unlock();
- }
-}
+++ /dev/null
-// Created on: 2011-02-03
-// Created by: Mikhail SAZONOV
-// Copyright (c) 2011-2014 OPEN CASCADE SAS
-//
-// This file is part of Open CASCADE Technology software library.
-//
-// This library is free software; you can redistribute it and/or modify it under
-// the terms of the GNU Lesser General Public License version 2.1 as published
-// by the Free Software Foundation, with special exception defined in the file
-// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
-// distribution for complete text of the license and disclaimer of any warranty.
-//
-// Alternatively, this file may be used under the terms of Open CASCADE
-// commercial license or contractual agreement.
-
-#ifndef _OSD_MAllocHook_HeaderFile
-#define _OSD_MAllocHook_HeaderFile
-
-#include <Standard_Mutex.hxx>
-#include <fstream>
-
-/**
- * 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:
- std::ofstream 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);
-
- public:
- struct Numbers
- {
- int nbAlloc;
- int nbFree;
- int nbLeftPeak;
-
- Numbers()
- : nbAlloc(0),
- nbFree(0),
- nbLeftPeak(0)
- {
- }
- };
-
- static const size_t myMaxAllocSize; //!< maximum tracked size
-
- Standard_Mutex myMutex; //!< used for thread-safe access
- Numbers* myArray; //!< indexed from 0 to myMaxAllocSize-1
- ptrdiff_t myTotalLeftSize; //!< currently remained allocated size
- size_t myTotalPeakSize; //!< maximum cumulative allocated size
- // clang-format off
- size_t myBreakSize; //!< user defined allocation size to debug (see place_for_breakpoint())
- // clang-format on
- size_t myBreakPeak; //!< user defined peak size limit to debug
- };
-
- //! 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 */