1 // Created on: 2011-02-04
2 // Created by: Mikhail SAZONOV
3 // Copyright (c) 2011-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <OSD_MAllocHook.hxx>
19 #if !defined __STDC_LIMIT_MACROS
20 #define __STDC_LIMIT_MACROS
32 #define SIZE_MAX UINT_MAX
37 static OSD_MAllocHook::Callback* MypCurrentCallback = NULL;
40 // dummy function to call at place where break point might be needed
41 static unsigned debug_counter = 0;
42 inline void place_for_breakpoint () {
43 // this statement is just to have any instruction in object code,
44 // otherwise compiler does not leave a place for break point
49 //=======================================================================
50 //function : GetCallback
52 //=======================================================================
54 OSD_MAllocHook::Callback* OSD_MAllocHook::GetCallback()
56 return MypCurrentCallback;
59 //=======================================================================
60 //function : GetLogFileHandler
62 //=======================================================================
64 OSD_MAllocHook::LogFileHandler* OSD_MAllocHook::GetLogFileHandler()
66 static LogFileHandler MyHandler;
70 //=======================================================================
71 //function : GetCollectBySize
73 //=======================================================================
75 OSD_MAllocHook::CollectBySize* OSD_MAllocHook::GetCollectBySize()
77 static CollectBySize MyHandler;
81 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
82 // Platform-dependent methods
83 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
88 #if _MSC_VER >= 1500 /* VS 2008 */
90 static long getRequestNum(void* pvData, long lRequest, size_t& theSize)
92 #ifdef _DEBUG /* protect against invalid pointer; in Release, _CrtIsValidHeapPointer is always 1 */
93 if (!_CrtIsValidHeapPointer(pvData))
96 (void)lRequest; // avoid compiler warning on unused arg
99 #define nNoMansLandSize 4
100 // the header struct is taken from crt/src/dbgint.h
101 struct _CrtMemBlockHeader
111 unsigned char gap[nNoMansLandSize];
114 _CrtMemBlockHeader* aHeader = ((_CrtMemBlockHeader*)pvData)-1;
115 theSize = aHeader->nDataSize;
116 return aHeader->lRequest;
119 #else /* _MSC_VER < 1500 */
121 static long getRequestNum(void* /*pvData*/, long lRequest, size_t& /*theSize*/)
126 #endif /* _MSC_VER == 1500 */
128 int __cdecl MyAllocHook(int nAllocType,
133 const unsigned char * /*szFileName*/,
136 if (nBlockUse == _CRT_BLOCK || // Ignore internal C runtime library allocations
137 MypCurrentCallback == NULL)
140 if (nAllocType == _HOOK_ALLOC)
141 MypCurrentCallback->AllocEvent(nSize, lRequest);
142 else if (nAllocType == _HOOK_FREE)
144 // for free hook, lRequest is not defined,
145 // but we can take it from the CRT mem block header
147 lRequest = getRequestNum(pvData, lRequest, aSize);
148 MypCurrentCallback->FreeEvent(pvData, aSize, lRequest);
150 else // _HOOK_REALLOC
152 // for realloc hook, lRequest shows the new request,
153 // and we should get request number for old block
154 size_t anOldSize = 0;
155 long anOldRequest = getRequestNum(pvData, 0, anOldSize);
156 MypCurrentCallback->FreeEvent(pvData, anOldSize, anOldRequest);
157 MypCurrentCallback->AllocEvent(nSize, lRequest);
160 return(1); // Allow the memory operation to proceed
163 //=======================================================================
164 //function : SetCallback
166 //=======================================================================
168 void OSD_MAllocHook::SetCallback(Callback* theCB)
170 MypCurrentCallback = theCB;
172 _CrtSetAllocHook(NULL);
174 _CrtSetAllocHook(MyAllocHook);
179 // Not yet implemented for non-WNT platform
181 void OSD_MAllocHook::SetCallback(Callback* theCB)
183 MypCurrentCallback = theCB;
188 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
189 // LogFileHandler handler methods
190 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
192 //=======================================================================
193 //function : LogFileHandler::LogFileHandler
195 //=======================================================================
197 OSD_MAllocHook::LogFileHandler::LogFileHandler()
200 myLogFile.imbue (std::locale ("C"));
203 //=======================================================================
204 //function : LogFileHandler::~LogFileHandler
206 //=======================================================================
208 OSD_MAllocHook::LogFileHandler::~LogFileHandler()
213 //=======================================================================
214 //function : LogFileHandler::Open
216 //=======================================================================
218 Standard_Boolean OSD_MAllocHook::LogFileHandler::Open(const char* theFileName)
221 myLogFile.open (theFileName);
222 if (!myLogFile.is_open())
224 return Standard_False;
227 myLogFile << "Operation type; Request Number; Block Size\n"
228 "------------------------------------------\n";
229 return Standard_True;
232 //=======================================================================
233 //function : LogFileHandler::Close
235 //=======================================================================
237 void OSD_MAllocHook::LogFileHandler::Close()
239 if (myLogFile.is_open())
245 //=======================================================================
246 //function : LogFileHandler::MakeReport
248 //=======================================================================
253 Standard_Integer nbAlloc;
254 Standard_Integer nbFree;
255 Standard_Integer nbLeftPeak;
256 std::set<unsigned long> alive;
258 StorageInfo(Standard_Size theSize = 0)
267 bool operator < (const StorageInfo& theOther) const
269 return size < theOther.size;
273 Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport
274 (const char* theLogFile,
275 const char* theOutFile,
276 const Standard_Boolean theIncludeAlive)
279 FILE* aLogFile = fopen(theLogFile, "r");
280 if (aLogFile == NULL)
281 return Standard_False;
283 // skip 2 header lines
285 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
288 return Standard_False;
290 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
293 return Standard_False;
297 size_t aTotalLeftSize = 0;
298 size_t aTotalPeakSize = 0;
299 std::set<StorageInfo> aStMap;
300 while (fgets(aStr, MAX_STR-1, aLogFile) != NULL)
302 // detect operation type, request number and block size
303 unsigned long aReqNum, aSize;
306 //sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
307 while (*pStr != ' ' && *pStr) pStr++;
309 while (*pStr == ' ' && *pStr) pStr++;
310 aReqNum = atol(pStr);
311 while (*pStr != ' ' && *pStr) pStr++;
312 while (*pStr == ' ' && *pStr) pStr++;
314 Standard_Boolean isAlloc = Standard_False;
315 if (strcmp(aType, "alloc") == 0)
317 isAlloc = Standard_True;
319 else if (strcmp(aType, "free") != 0)
322 // collect statistics by storage size
323 StorageInfo aSuchInfo(aSize);
324 std::set<StorageInfo>::iterator aFound = aStMap.find(aSuchInfo);
325 if (aFound == aStMap.end())
326 aFound = aStMap.insert(aSuchInfo).first;
327 StorageInfo& aInfo = const_cast<StorageInfo&>(*aFound);
330 if (aInfo.nbAlloc + 1 > 0)
332 aTotalLeftSize += aSize;
333 if (aTotalLeftSize > aTotalPeakSize)
334 aTotalPeakSize = aTotalLeftSize;
335 int nbLeft = aInfo.nbAlloc - aInfo.nbFree;
336 if (nbLeft > aInfo.nbLeftPeak)
337 aInfo.nbLeftPeak = nbLeft;
338 aInfo.alive.insert(aReqNum);
342 std::set<unsigned long>::iterator aFoundReqNum =
343 aInfo.alive.find(aReqNum);
344 if (aFoundReqNum == aInfo.alive.end())
345 // freeing non-registered block, skip it
347 aTotalLeftSize -= aSize;
348 aInfo.alive.erase(aFoundReqNum);
349 if (aInfo.nbAlloc + 1 > 0)
356 std::ofstream aRepFile (theOutFile);
357 if(!aRepFile.is_open())
359 return Standard_False;
361 aRepFile.imbue (std::locale ("C"));
363 aRepFile << std::setw(20) << "BlockSize "
364 << std::setw(10) << "NbAlloc "
365 << std::setw(10) << "NbLeft "
366 << std::setw(10) << "NbLeftPeak "
367 << std::setw(20) << "AllocSize "
368 << std::setw(20) << "LeftSize "
369 << std::setw(20) << "PeakSize " << std::endl;
371 Standard_Size aTotAlloc = 0;
372 for (std::set<StorageInfo>::const_iterator it = aStMap.begin();
373 it != aStMap.end(); ++it)
375 const StorageInfo& aInfo = *it;
376 Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
377 Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.size;
378 Standard_Size aSizeLeft = nbLeft * aInfo.size;
379 Standard_Size aSizePeak = aInfo.nbLeftPeak * aInfo.size;
381 aRepFile << std::setw(20) << aInfo.size << ' '
382 << std::setw(10) << aInfo.nbAlloc << ' '
383 << std::setw(10) << nbLeft << ' '
384 << std::setw(10) << aInfo.nbLeftPeak << ' '
385 << std::setw(20) << aSizeAlloc << ' '
386 << std::setw(20) << aSizeLeft << ' '
387 << std::setw(20) << aSizePeak << std::endl;
389 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
390 aTotAlloc = SIZE_MAX;
392 aTotAlloc += aSizeAlloc;
393 if (theIncludeAlive && !aInfo.alive.empty())
395 for (std::set<unsigned long>::const_iterator it1 = aInfo.alive.begin();
396 it1 != aInfo.alive.end(); ++it1)
397 aRepFile << std::setw(10) << *it1;
400 aRepFile << std::setw(20) << "Total:"
401 << std::setw(10) << "" << ' '
402 << std::setw(10) << "" << ' '
403 << std::setw(10) << "" << ' '
404 << (aTotAlloc == SIZE_MAX ? '>' : ' ')
405 << std::setw(20) << aTotAlloc << ' '
406 << std::setw(20) << aTotalLeftSize << ' '
407 << std::setw(20) << aTotalPeakSize << std::endl;
410 return Standard_True;
413 //=======================================================================
414 //function : LogFileHandler::AllocEvent
416 //=======================================================================
418 void OSD_MAllocHook::LogFileHandler::AllocEvent
422 if (myLogFile.is_open())
425 myLogFile << "alloc "<< std::setw(10) << theRequestNum
426 << std::setw(20) << theSize << std::endl;
427 if (myBreakSize == theSize)
428 place_for_breakpoint();
433 //=======================================================================
434 //function : LogFileHandler::FreeEvent
436 //=======================================================================
438 void OSD_MAllocHook::LogFileHandler::FreeEvent
443 if (myLogFile.is_open())
446 myLogFile << "free " << std::setw(20) << theRequestNum
447 << std::setw(20) << theSize << std::endl;
452 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
453 // CollectBySize handler methods
454 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
456 //=======================================================================
457 //function : CollectBySize::CollectBySize
459 //=======================================================================
461 OSD_MAllocHook::CollectBySize::CollectBySize()
471 //=======================================================================
472 //function : CollectBySize::~CollectBySize
474 //=======================================================================
476 OSD_MAllocHook::CollectBySize::~CollectBySize()
482 //=======================================================================
483 //function : CollectBySize::Reset
485 //=======================================================================
487 #define MAX_ALLOC_SIZE 2000000
488 const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
490 void OSD_MAllocHook::CollectBySize::Reset()
494 myArray = new Numbers[MAX_ALLOC_SIZE];
497 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
498 myArray[i] = Numbers();
505 //=======================================================================
506 //function : CollectBySize::MakeReport
508 //=======================================================================
510 Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
513 std::ofstream aRepFile(theOutFile);
514 if (!aRepFile.is_open())
515 return Standard_False;
516 std::locale aCLoc("C");
517 aRepFile.imbue(aCLoc);
519 aRepFile << std::setw(10) << "BlockSize "
520 << std::setw(10) << "NbAlloc "
521 << std::setw(10) << "NbLeft "
522 << std::setw(10) << "NbLeftPeak "
523 << std::setw(20) << "AllocSize "
524 << std::setw(20) << "LeftSize "
525 << std::setw(20) << "PeakSize " << std::endl;
527 Standard_Size aTotAlloc = 0;
528 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
530 if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
532 Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
534 Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
535 ptrdiff_t aSizeLeft = nbLeft * aSize;
536 Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
538 aRepFile << std::setw(10) << aSize << ' '
539 << std::setw(10) << myArray[i].nbAlloc << ' '
540 << std::setw(10) << nbLeft << ' '
541 << std::setw(10) << myArray[i].nbLeftPeak << ' '
542 << std::setw(20) << aSizeAlloc << ' '
543 << std::setw(20) << aSizeLeft << ' '
544 << std::setw(20) << aSizePeak << std::endl;
546 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
547 aTotAlloc = SIZE_MAX;
549 aTotAlloc += aSizeAlloc;
552 aRepFile << std::setw(10) << "Total:" << ' '
553 << std::setw(10) << "" << ' '
554 << std::setw(10) << "" << ' '
555 << std::setw(10) << "" << ' '
556 << (aTotAlloc == SIZE_MAX ? '>' : ' ')
557 << std::setw(20) << aTotAlloc << ' '
558 << std::setw(20) << myTotalLeftSize << ' '
559 << std::setw(20) << myTotalPeakSize << std::endl;
561 return Standard_True;
564 //=======================================================================
565 //function : CollectBySize::AllocEvent
567 //=======================================================================
569 void OSD_MAllocHook::CollectBySize::AllocEvent
571 long /*theRequestNum*/)
573 if (myBreakSize == theSize)
574 place_for_breakpoint();
578 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
579 myArray[ind].nbAlloc++;
580 myTotalLeftSize += theSize;
581 int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
582 if (nbLeft > myArray[ind].nbLeftPeak)
584 myArray[ind].nbLeftPeak = nbLeft;
586 && (myBreakSize == theSize || myBreakSize == 0))
588 const Standard_Size aSizePeak = myArray[ind].nbLeftPeak * theSize;
589 if (aSizePeak > myBreakPeak)
591 place_for_breakpoint();
595 if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
596 myTotalPeakSize = myTotalLeftSize;
601 //=======================================================================
602 //function : CollectBySize::FreeEvent
604 //=======================================================================
606 void OSD_MAllocHook::CollectBySize::FreeEvent
609 long /*theRequestNum*/)
614 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
615 myArray[ind].nbFree++;
616 myTotalLeftSize -= theSize;