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 //=======================================================================
254 Standard_Integer nbAlloc;
255 Standard_Integer nbFree;
256 Standard_Integer nbLeftPeak;
257 std::set<unsigned long> alive;
259 StorageInfo(Standard_Size theSize = 0)
268 bool operator < (const StorageInfo& theOther) const
270 return size < theOther.size;
275 Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport
276 (const char* theLogFile,
277 const char* theOutFile,
278 const Standard_Boolean theIncludeAlive)
281 FILE* aLogFile = fopen(theLogFile, "r");
282 if (aLogFile == NULL)
283 return Standard_False;
285 // skip 2 header lines
287 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
290 return Standard_False;
292 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
295 return Standard_False;
299 size_t aTotalLeftSize = 0;
300 size_t aTotalPeakSize = 0;
301 std::set<StorageInfo> aStMap;
302 while (fgets(aStr, MAX_STR-1, aLogFile) != NULL)
304 // detect operation type, request number and block size
305 unsigned long aReqNum, aSize;
308 //sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
309 while (*pStr != ' ' && *pStr) pStr++;
311 while (*pStr == ' ' && *pStr) pStr++;
312 aReqNum = atol(pStr);
313 while (*pStr != ' ' && *pStr) pStr++;
314 while (*pStr == ' ' && *pStr) pStr++;
316 Standard_Boolean isAlloc = Standard_False;
317 if (strcmp(aType, "alloc") == 0)
319 isAlloc = Standard_True;
321 else if (strcmp(aType, "free") != 0)
324 // collect statistics by storage size
325 StorageInfo aSuchInfo(aSize);
326 std::set<StorageInfo>::iterator aFound = aStMap.find(aSuchInfo);
327 if (aFound == aStMap.end())
328 aFound = aStMap.insert(aSuchInfo).first;
329 StorageInfo& aInfo = const_cast<StorageInfo&>(*aFound);
332 if (aInfo.nbAlloc + 1 > 0)
334 aTotalLeftSize += aSize;
335 if (aTotalLeftSize > aTotalPeakSize)
336 aTotalPeakSize = aTotalLeftSize;
337 int nbLeft = aInfo.nbAlloc - aInfo.nbFree;
338 if (nbLeft > aInfo.nbLeftPeak)
339 aInfo.nbLeftPeak = nbLeft;
340 aInfo.alive.insert(aReqNum);
344 std::set<unsigned long>::iterator aFoundReqNum =
345 aInfo.alive.find(aReqNum);
346 if (aFoundReqNum == aInfo.alive.end())
347 // freeing non-registered block, skip it
349 aTotalLeftSize -= aSize;
350 aInfo.alive.erase(aFoundReqNum);
351 if (aInfo.nbAlloc + 1 > 0)
358 std::ofstream aRepFile (theOutFile);
359 if(!aRepFile.is_open())
361 return Standard_False;
363 aRepFile.imbue (std::locale ("C"));
365 aRepFile << std::setw(20) << "BlockSize "
366 << std::setw(10) << "NbAlloc "
367 << std::setw(10) << "NbLeft "
368 << std::setw(10) << "NbLeftPeak "
369 << std::setw(20) << "AllocSize "
370 << std::setw(20) << "LeftSize "
371 << std::setw(20) << "PeakSize " << std::endl;
373 Standard_Size aTotAlloc = 0;
374 for (std::set<StorageInfo>::const_iterator it = aStMap.begin();
375 it != aStMap.end(); ++it)
377 const StorageInfo& aInfo = *it;
378 Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
379 Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.size;
380 Standard_Size aSizeLeft = nbLeft * aInfo.size;
381 Standard_Size aSizePeak = aInfo.nbLeftPeak * aInfo.size;
383 aRepFile << std::setw(20) << aInfo.size << ' '
384 << std::setw(10) << aInfo.nbAlloc << ' '
385 << std::setw(10) << nbLeft << ' '
386 << std::setw(10) << aInfo.nbLeftPeak << ' '
387 << std::setw(20) << aSizeAlloc << ' '
388 << std::setw(20) << aSizeLeft << ' '
389 << std::setw(20) << aSizePeak << std::endl;
391 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
392 aTotAlloc = SIZE_MAX;
394 aTotAlloc += aSizeAlloc;
395 if (theIncludeAlive && !aInfo.alive.empty())
397 for (std::set<unsigned long>::const_iterator it1 = aInfo.alive.begin();
398 it1 != aInfo.alive.end(); ++it1)
399 aRepFile << std::setw(10) << *it1;
402 aRepFile << std::setw(20) << "Total:"
403 << std::setw(10) << "" << ' '
404 << std::setw(10) << "" << ' '
405 << std::setw(10) << "" << ' '
406 << (aTotAlloc == SIZE_MAX ? '>' : ' ')
407 << std::setw(20) << aTotAlloc << ' '
408 << std::setw(20) << aTotalLeftSize << ' '
409 << std::setw(20) << aTotalPeakSize << std::endl;
412 return Standard_True;
415 //=======================================================================
416 //function : LogFileHandler::AllocEvent
418 //=======================================================================
420 void OSD_MAllocHook::LogFileHandler::AllocEvent
424 if (myLogFile.is_open())
427 myLogFile << "alloc "<< std::setw(10) << theRequestNum
428 << std::setw(20) << theSize << std::endl;
429 if (myBreakSize == theSize)
430 place_for_breakpoint();
435 //=======================================================================
436 //function : LogFileHandler::FreeEvent
438 //=======================================================================
440 void OSD_MAllocHook::LogFileHandler::FreeEvent
445 if (myLogFile.is_open())
448 myLogFile << "free " << std::setw(20) << theRequestNum
449 << std::setw(20) << theSize << std::endl;
454 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
455 // CollectBySize handler methods
456 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
458 //=======================================================================
459 //function : CollectBySize::CollectBySize
461 //=======================================================================
463 OSD_MAllocHook::CollectBySize::CollectBySize()
473 //=======================================================================
474 //function : CollectBySize::~CollectBySize
476 //=======================================================================
478 OSD_MAllocHook::CollectBySize::~CollectBySize()
484 //=======================================================================
485 //function : CollectBySize::Reset
487 //=======================================================================
489 #define MAX_ALLOC_SIZE 2000000
490 const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
492 void OSD_MAllocHook::CollectBySize::Reset()
496 myArray = new Numbers[MAX_ALLOC_SIZE];
499 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
500 myArray[i] = Numbers();
507 //=======================================================================
508 //function : CollectBySize::MakeReport
510 //=======================================================================
512 Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
515 std::ofstream aRepFile(theOutFile);
516 if (!aRepFile.is_open())
517 return Standard_False;
518 std::locale aCLoc("C");
519 aRepFile.imbue(aCLoc);
521 aRepFile << std::setw(10) << "BlockSize "
522 << std::setw(10) << "NbAlloc "
523 << std::setw(10) << "NbLeft "
524 << std::setw(10) << "NbLeftPeak "
525 << std::setw(20) << "AllocSize "
526 << std::setw(20) << "LeftSize "
527 << std::setw(20) << "PeakSize " << std::endl;
529 Standard_Size aTotAlloc = 0;
530 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
532 if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
534 Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
536 Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
537 ptrdiff_t aSizeLeft = nbLeft * aSize;
538 Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
540 aRepFile << std::setw(10) << aSize << ' '
541 << std::setw(10) << myArray[i].nbAlloc << ' '
542 << std::setw(10) << nbLeft << ' '
543 << std::setw(10) << myArray[i].nbLeftPeak << ' '
544 << std::setw(20) << aSizeAlloc << ' '
545 << std::setw(20) << aSizeLeft << ' '
546 << std::setw(20) << aSizePeak << std::endl;
548 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
549 aTotAlloc = SIZE_MAX;
551 aTotAlloc += aSizeAlloc;
554 aRepFile << std::setw(10) << "Total:" << ' '
555 << std::setw(10) << "" << ' '
556 << std::setw(10) << "" << ' '
557 << std::setw(10) << "" << ' '
558 << (aTotAlloc == SIZE_MAX ? '>' : ' ')
559 << std::setw(20) << aTotAlloc << ' '
560 << std::setw(20) << myTotalLeftSize << ' '
561 << std::setw(20) << myTotalPeakSize << std::endl;
563 return Standard_True;
566 //=======================================================================
567 //function : CollectBySize::AllocEvent
569 //=======================================================================
571 void OSD_MAllocHook::CollectBySize::AllocEvent
573 long /*theRequestNum*/)
575 if (myBreakSize == theSize)
576 place_for_breakpoint();
580 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
581 myArray[ind].nbAlloc++;
582 myTotalLeftSize += theSize;
583 int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
584 if (nbLeft > myArray[ind].nbLeftPeak)
586 myArray[ind].nbLeftPeak = nbLeft;
588 && (myBreakSize == theSize || myBreakSize == 0))
590 const Standard_Size aSizePeak = myArray[ind].nbLeftPeak * theSize;
591 if (aSizePeak > myBreakPeak)
593 place_for_breakpoint();
597 if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
598 myTotalPeakSize = myTotalLeftSize;
603 //=======================================================================
604 //function : CollectBySize::FreeEvent
606 //=======================================================================
608 void OSD_MAllocHook::CollectBySize::FreeEvent
611 long /*theRequestNum*/)
616 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
617 myArray[ind].nbFree++;
618 myTotalLeftSize -= theSize;