1 // Created on: 2011-02-04
2 // Created by: Mikhail SAZONOV
3 // Copyright (c) 2011-2012 OPEN CASCADE SAS
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
21 #include <OSD_MAllocHook.hxx>
24 #if !defined __STDC_LIMIT_MACROS
25 #define __STDC_LIMIT_MACROS
35 #define SIZE_MAX UINT_MAX
40 static OSD_MAllocHook::Callback* MypCurrentCallback = NULL;
42 //=======================================================================
43 //function : GetCallback
45 //=======================================================================
47 OSD_MAllocHook::Callback* OSD_MAllocHook::GetCallback()
49 return MypCurrentCallback;
52 //=======================================================================
53 //function : GetLogFileHandler
55 //=======================================================================
57 OSD_MAllocHook::LogFileHandler* OSD_MAllocHook::GetLogFileHandler()
59 static LogFileHandler MyHandler;
63 //=======================================================================
64 //function : GetCollectBySize
66 //=======================================================================
68 OSD_MAllocHook::CollectBySize* OSD_MAllocHook::GetCollectBySize()
70 static CollectBySize MyHandler;
74 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
75 // Platform-dependent methods
76 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
81 static long getRequestNum(void* pvData, long lRequest, size_t& theSize)
83 if (_CrtIsValidHeapPointer(pvData))
85 #if _MSC_VER == 1500 // VS 2008
86 #define nNoMansLandSize 4
87 // the header struct is taken from crt/src/dbgint.h
88 struct _CrtMemBlockHeader
98 unsigned char gap[nNoMansLandSize];
100 _CrtMemBlockHeader* aHeader = ((_CrtMemBlockHeader*)pvData)-1;
101 theSize = aHeader->nDataSize;
102 return aHeader->lRequest;
108 int __cdecl MyAllocHook(int nAllocType,
113 const unsigned char * /*szFileName*/,
116 if (nBlockUse == _CRT_BLOCK || // Ignore internal C runtime library allocations
117 MypCurrentCallback == NULL)
120 if (nAllocType == _HOOK_ALLOC)
121 MypCurrentCallback->AllocEvent(nSize, lRequest);
122 else if (nAllocType == _HOOK_FREE)
124 // for free hook, lRequest is not defined,
125 // but we can take it from the CRT mem block header
127 lRequest = getRequestNum(pvData, lRequest, aSize);
128 MypCurrentCallback->FreeEvent(pvData, aSize, lRequest);
130 else // _HOOK_REALLOC
132 // for realloc hook, lRequest shows the new request,
133 // and we should get request number for old block
134 size_t anOldSize = 0;
135 long anOldRequest = getRequestNum(pvData, 0, anOldSize);
136 MypCurrentCallback->FreeEvent(pvData, anOldSize, anOldRequest);
137 MypCurrentCallback->AllocEvent(nSize, lRequest);
140 return(1); // Allow the memory operation to proceed
143 //=======================================================================
144 //function : SetCallback
146 //=======================================================================
148 void OSD_MAllocHook::SetCallback(Callback* theCB)
150 MypCurrentCallback = theCB;
152 _CrtSetAllocHook(NULL);
154 _CrtSetAllocHook(MyAllocHook);
159 // Not yet implemented for non-WNT platform
161 void OSD_MAllocHook::SetCallback(Callback* theCB)
163 MypCurrentCallback = theCB;
168 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
169 // LogFileHandler handler methods
170 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
172 //=======================================================================
173 //function : LogFileHandler::LogFileHandler
175 //=======================================================================
177 OSD_MAllocHook::LogFileHandler::LogFileHandler()
183 //=======================================================================
184 //function : LogFileHandler::~LogFileHandler
186 //=======================================================================
188 OSD_MAllocHook::LogFileHandler::~LogFileHandler()
193 //=======================================================================
194 //function : LogFileHandler::Open
196 //=======================================================================
198 Standard_Boolean OSD_MAllocHook::LogFileHandler::Open(const char* theFileName)
201 myLogFile = fopen(theFileName, "w");
202 if (myLogFile != NULL)
204 fputs("Operation type; Request Number; Block Size\n", myLogFile);
205 fputs("------------------------------------------\n", myLogFile);
207 return myLogFile != NULL;
210 //=======================================================================
211 //function : LogFileHandler::Close
213 //=======================================================================
215 void OSD_MAllocHook::LogFileHandler::Close()
217 if (myLogFile != NULL)
224 //=======================================================================
225 //function : LogFileHandler::MakeReport
227 //=======================================================================
235 std::set<unsigned long>* alive;
237 : size(0), nbAlloc(0), nbFree(0), nbLeftPeak(0), alive(NULL) {}
238 StorageInfo(Standard_Size theSize)
239 : size(theSize), nbAlloc(0), nbFree(0), nbLeftPeak(0), alive(NULL) {}
245 std::set<unsigned long>& Alive()
248 alive = new std::set<unsigned long>;
251 const std::set<unsigned long>& Alive() const
257 inline bool operator < (const StorageInfo& one, const StorageInfo& two)
259 return one.size < two.size;
262 Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport
263 (const char* theLogFile,
264 const char* theOutFile,
265 const Standard_Boolean theIncludeAlive)
268 FILE* aLogFile = fopen(theLogFile, "r");
269 if (aLogFile == NULL)
270 return Standard_False;
272 // skip 2 header lines
274 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
277 return Standard_False;
279 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
282 return Standard_False;
286 size_t aTotalLeftSize = 0;
287 size_t aTotalPeakSize = 0;
288 std::set<StorageInfo> aStMap;
289 while (fgets(aStr, MAX_STR-1, aLogFile) != NULL)
291 // detect operation type, request number and block size
292 unsigned long aReqNum, aSize;
295 //sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
296 while (*pStr != ' ' && *pStr) pStr++;
298 while (*pStr == ' ' && *pStr) pStr++;
299 aReqNum = atol(pStr);
300 while (*pStr != ' ' && *pStr) pStr++;
301 while (*pStr == ' ' && *pStr) pStr++;
303 Standard_Boolean isAlloc = Standard_False;
304 if (strcmp(aType, "alloc") == 0)
306 isAlloc = Standard_True;
308 else if (strcmp(aType, "free") != 0)
311 // collect statistics by storage size
312 StorageInfo aSuchInfo(aSize);
313 std::set<StorageInfo>::iterator aFound = aStMap.find(aSuchInfo);
314 if (aFound == aStMap.end())
315 aFound = aStMap.insert(aSuchInfo).first;
316 StorageInfo& aInfo = const_cast<StorageInfo&>(*aFound);
319 if (aInfo.nbAlloc + 1 > 0)
321 aTotalLeftSize += aSize;
322 if (aTotalLeftSize > aTotalPeakSize)
323 aTotalPeakSize = aTotalLeftSize;
324 int nbLeft = aInfo.nbAlloc - aInfo.nbFree;
325 if (nbLeft > aInfo.nbLeftPeak)
326 aInfo.nbLeftPeak = nbLeft;
327 aInfo.Alive().insert(aReqNum);
331 std::set<unsigned long>::iterator aFoundReqNum =
332 aInfo.Alive().find(aReqNum);
333 if (aFoundReqNum == aInfo.Alive().end())
334 // freeing non-registered block, skip it
336 aTotalLeftSize -= aSize;
337 aInfo.Alive().erase(aFoundReqNum);
338 if (aInfo.nbAlloc + 1 > 0)
345 FILE* aRepFile = fopen(theOutFile, "w");
346 if (aRepFile == NULL)
347 return Standard_False;
348 fprintf(aRepFile, "%10s %10s %10s %10s %10s %10s %10s\n",
349 "BlockSize", "NbAlloc", "NbLeft", "NbLeftPeak",
350 "AllocSize", "LeftSize", "PeakSize");
351 Standard_Size aTotAlloc = 0;
352 for (std::set<StorageInfo>::const_iterator it = aStMap.begin();
353 it != aStMap.end(); ++it)
355 const StorageInfo& aInfo = *it;
356 Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
357 Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.size;
358 Standard_Size aSizeLeft = nbLeft * aInfo.size;
359 Standard_Size aSizePeak = aInfo.nbLeftPeak * aInfo.size;
360 fprintf(aRepFile, "%10d %10d %10d %10d %10Iu %10Iu %10Iu\n", aInfo.size,
361 aInfo.nbAlloc, nbLeft, aInfo.nbLeftPeak,
362 aSizeAlloc, aSizeLeft, aSizePeak);
363 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
364 aTotAlloc = SIZE_MAX;
366 aTotAlloc += aSizeAlloc;
367 if (theIncludeAlive && !aInfo.Alive().empty())
369 for (std::set<unsigned long>::const_iterator it1 = aInfo.alive->begin();
370 it1 != aInfo.alive->end(); ++it1)
371 fprintf(aRepFile, "%10lu\n", *it1);
374 fprintf(aRepFile, "%10s %10s %10s %10s%c%10Iu %10Iu %10Iu\n", "Total:",
375 "", "", "", (aTotAlloc == SIZE_MAX ? '>' : ' '), aTotAlloc,
376 aTotalLeftSize, aTotalPeakSize);
378 return Standard_True;
381 //=======================================================================
382 //function : LogFileHandler::AllocEvent
384 //=======================================================================
386 void OSD_MAllocHook::LogFileHandler::AllocEvent
390 if (myLogFile != NULL)
393 fprintf(myLogFile, "alloc %10lu %10u\n", theRequestNum, theSize);
395 if (myBreakSize == theSize)
402 //=======================================================================
403 //function : LogFileHandler::FreeEvent
405 //=======================================================================
407 void OSD_MAllocHook::LogFileHandler::FreeEvent
412 if (myLogFile != NULL)
415 fprintf(myLogFile, "free %10lu %10u\n", theRequestNum, theSize);
420 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
421 // CollectBySize handler methods
422 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
424 //=======================================================================
425 //function : CollectBySize::CollectBySize
427 //=======================================================================
429 OSD_MAllocHook::CollectBySize::CollectBySize()
438 //=======================================================================
439 //function : CollectBySize::~CollectBySize
441 //=======================================================================
443 OSD_MAllocHook::CollectBySize::~CollectBySize()
449 //=======================================================================
450 //function : CollectBySize::Reset
452 //=======================================================================
454 #define MAX_ALLOC_SIZE 2000000u
455 const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
457 void OSD_MAllocHook::CollectBySize::Reset()
461 myArray = new Numbers[MAX_ALLOC_SIZE];
464 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
465 myArray[i] = Numbers();
472 //=======================================================================
473 //function : CollectBySize::MakeReport
475 //=======================================================================
477 Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
480 FILE* aRepFile = fopen(theOutFile, "w");
481 if (aRepFile == NULL)
482 return Standard_False;
483 fprintf(aRepFile, "%10s %10s %10s %10s %10s %10s %10s\n",
484 "BlockSize", "NbAlloc", "NbLeft", "NbLeftPeak",
485 "AllocSize", "LeftSize", "PeakSize");
486 Standard_Size aTotAlloc = 0;
487 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
489 if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
491 Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
493 Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
494 ptrdiff_t aSizeLeft = nbLeft * aSize;
495 Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
496 fprintf(aRepFile, "%10d %10d %10d %10d %10Iu %10Id %10Iu\n", aSize,
497 myArray[i].nbAlloc, nbLeft, myArray[i].nbLeftPeak,
498 aSizeAlloc, aSizeLeft, aSizePeak);
499 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
500 aTotAlloc = SIZE_MAX;
502 aTotAlloc += aSizeAlloc;
505 fprintf(aRepFile, "%10s %10s %10s %10s%c%10Iu %10Id %10Iu\n", "Total:",
506 "", "", "", (aTotAlloc == SIZE_MAX ? '>' : ' '), aTotAlloc,
507 myTotalLeftSize, myTotalPeakSize);
509 return Standard_True;
512 //=======================================================================
513 //function : CollectBySize::AllocEvent
515 //=======================================================================
517 void OSD_MAllocHook::CollectBySize::AllocEvent
519 long /*theRequestNum*/)
521 if (myBreakSize == theSize)
528 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
529 myArray[ind].nbAlloc++;
530 myTotalLeftSize += theSize;
531 int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
532 if (nbLeft > myArray[ind].nbLeftPeak)
533 myArray[ind].nbLeftPeak = nbLeft;
534 if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
535 myTotalPeakSize = myTotalLeftSize;
540 //=======================================================================
541 //function : CollectBySize::FreeEvent
543 //=======================================================================
545 void OSD_MAllocHook::CollectBySize::FreeEvent
548 long /*theRequestNum*/)
553 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
554 myArray[ind].nbFree++;
555 myTotalLeftSize -= theSize;