mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-09-13 14:27:08 +03:00
Coding - Remove OSD_MAllocHook class (#707)
- Complete removal of the `OSD_MAllocHook` class and its related handler implementations - Removal of the Draw command "mallochook" that provided command-line interface to the memory tracking functionality - Updates to build configuration to exclude the removed files
This commit is contained in:
@@ -25,7 +25,6 @@
|
||||
#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>
|
||||
@@ -677,126 +676,6 @@ static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const
|
||||
|
||||
//=================================================================================================
|
||||
|
||||
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;
|
||||
@@ -1319,11 +1198,6 @@ void Draw::BasicCommands(Draw_Interpretor& theCommands)
|
||||
"\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",
|
||||
|
@@ -50,8 +50,6 @@ set(OCCT_OSD_FILES
|
||||
OSD_LocalFileSystem.cxx
|
||||
OSD_LocalFileSystem.hxx
|
||||
OSD_LockType.hxx
|
||||
OSD_MAllocHook.cxx
|
||||
OSD_MAllocHook.hxx
|
||||
OSD_MemInfo.cxx
|
||||
OSD_MemInfo.hxx
|
||||
OSD_OEMType.hxx
|
||||
|
@@ -1,545 +0,0 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
@@ -1,170 +0,0 @@
|
||||
// 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 */
|
Reference in New Issue
Block a user