0024512: clang++ compiler complains about extra semicolon
[occt.git] / src / OSD / OSD_MAllocHook.cxx
CommitLineData
b311480e 1// Created on: 2011-02-04
2// Created by: Mikhail SAZONOV
973c2be1 3// Copyright (c) 2011-2014 OPEN CASCADE SAS
b311480e 4//
973c2be1 5// This file is part of Open CASCADE Technology software library.
b311480e 6//
973c2be1 7// This library is free software; you can redistribute it and / or modify it
8// under the terms of the GNU Lesser General Public 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.
b311480e 12//
973c2be1 13// Alternatively, this file may be used under the terms of Open CASCADE
14// commercial license or contractual agreement.
b311480e 15
7af17f1e
MA
16#include <OSD_MAllocHook.hxx>
17
18#ifndef WNT
19#if !defined __STDC_LIMIT_MACROS
20#define __STDC_LIMIT_MACROS
21#endif
22#include <stdint.h>
23#endif
24
25#include <set>
26#include <map>
e2f8b392 27#include <cstdlib>
64531d9c 28#include <iomanip>
7af17f1e 29
213cb888
M
30#ifndef SIZE_MAX
31#define SIZE_MAX UINT_MAX
32#endif
33
7af17f1e
MA
34#define MAX_STR 80
35
36static OSD_MAllocHook::Callback* MypCurrentCallback = NULL;
37
302f96fb 38namespace {
39 // dummy function to call at place where break point might be needed
40 inline void place_for_breakpoint () {}
5640d653 41}
302f96fb 42
7af17f1e
MA
43//=======================================================================
44//function : GetCallback
45//purpose :
46//=======================================================================
47
48OSD_MAllocHook::Callback* OSD_MAllocHook::GetCallback()
49{
50 return MypCurrentCallback;
51}
52
53//=======================================================================
54//function : GetLogFileHandler
55//purpose :
56//=======================================================================
57
58OSD_MAllocHook::LogFileHandler* OSD_MAllocHook::GetLogFileHandler()
59{
60 static LogFileHandler MyHandler;
61 return &MyHandler;
62}
63
64//=======================================================================
65//function : GetCollectBySize
66//purpose :
67//=======================================================================
68
69OSD_MAllocHook::CollectBySize* OSD_MAllocHook::GetCollectBySize()
70{
71 static CollectBySize MyHandler;
72 return &MyHandler;
73}
74
75//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
76// Platform-dependent methods
77//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
78
79#ifdef WNT
80#include <crtdbg.h>
81
295cb053 82#if _MSC_VER == 1500 /* VS 2008 */
83
7af17f1e
MA
84static long getRequestNum(void* pvData, long lRequest, size_t& theSize)
85{
295cb053 86#ifdef _DEBUG /* protect against invalid pointer; in Release, _CrtIsValidHeapPointer is always 1 */
87 if (!_CrtIsValidHeapPointer(pvData))
88 return lRequest;
89#else
90 (void)lRequest; // avoid compiler warning on unused arg
105aae76 91#endif
295cb053 92
7af17f1e 93#define nNoMansLandSize 4
295cb053 94 // the header struct is taken from crt/src/dbgint.h
95 struct _CrtMemBlockHeader
96 {
7af17f1e 97#ifdef _WIN64
295cb053 98 int nBlockUse;
99 size_t nDataSize;
7af17f1e 100#else
295cb053 101 size_t nDataSize;
102 int nBlockUse;
105aae76 103#endif
295cb053 104 long lRequest;
105 unsigned char gap[nNoMansLandSize];
106 };
107
108 _CrtMemBlockHeader* aHeader = ((_CrtMemBlockHeader*)pvData)-1;
109 theSize = aHeader->nDataSize;
110 return aHeader->lRequest;
111}
112
113#else /* _MSC_VER == 1500 */
114
115static long getRequestNum(void* /*pvData*/, long lRequest, size_t& /*theSize*/)
116{
7af17f1e
MA
117 return lRequest;
118}
119
295cb053 120#endif /* _MSC_VER == 1500 */
121
7af17f1e
MA
122int __cdecl MyAllocHook(int nAllocType,
123 void * pvData,
124 size_t nSize,
125 int nBlockUse,
126 long lRequest,
127 const unsigned char * /*szFileName*/,
128 int /*nLine*/)
129{
130 if (nBlockUse == _CRT_BLOCK || // Ignore internal C runtime library allocations
131 MypCurrentCallback == NULL)
132 return(1);
133
134 if (nAllocType == _HOOK_ALLOC)
135 MypCurrentCallback->AllocEvent(nSize, lRequest);
136 else if (nAllocType == _HOOK_FREE)
137 {
138 // for free hook, lRequest is not defined,
139 // but we can take it from the CRT mem block header
140 size_t aSize = 0;
141 lRequest = getRequestNum(pvData, lRequest, aSize);
142 MypCurrentCallback->FreeEvent(pvData, aSize, lRequest);
143 }
144 else // _HOOK_REALLOC
145 {
146 // for realloc hook, lRequest shows the new request,
147 // and we should get request number for old block
148 size_t anOldSize = 0;
149 long anOldRequest = getRequestNum(pvData, 0, anOldSize);
150 MypCurrentCallback->FreeEvent(pvData, anOldSize, anOldRequest);
151 MypCurrentCallback->AllocEvent(nSize, lRequest);
152 }
153
154 return(1); // Allow the memory operation to proceed
155}
156
157//=======================================================================
158//function : SetCallback
159//purpose :
160//=======================================================================
161
162void OSD_MAllocHook::SetCallback(Callback* theCB)
163{
164 MypCurrentCallback = theCB;
165 if (theCB == NULL)
166 _CrtSetAllocHook(NULL);
167 else
168 _CrtSetAllocHook(MyAllocHook);
169}
170
171#else // ! WNT
172
173// Not yet implemented for non-WNT platform
174
175void OSD_MAllocHook::SetCallback(Callback* theCB)
176{
177 MypCurrentCallback = theCB;
178}
179
180#endif // WNT
181
182//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
183// LogFileHandler handler methods
184//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
185
186//=======================================================================
187//function : LogFileHandler::LogFileHandler
188//purpose :
189//=======================================================================
190
191OSD_MAllocHook::LogFileHandler::LogFileHandler()
64531d9c 192: myBreakSize(0)
7af17f1e 193{
64531d9c 194 myLogFile.imbue (std::locale ("C"));
7af17f1e
MA
195}
196
197//=======================================================================
198//function : LogFileHandler::~LogFileHandler
199//purpose :
200//=======================================================================
201
202OSD_MAllocHook::LogFileHandler::~LogFileHandler()
203{
204 Close();
205}
206
207//=======================================================================
208//function : LogFileHandler::Open
209//purpose :
210//=======================================================================
211
212Standard_Boolean OSD_MAllocHook::LogFileHandler::Open(const char* theFileName)
213{
214 Close();
64531d9c 215 myLogFile.open (theFileName);
216 if (!myLogFile.is_open())
7af17f1e 217 {
64531d9c 218 return Standard_False;
7af17f1e 219 }
64531d9c 220
221 myLogFile << "Operation type; Request Number; Block Size\n"
222 "------------------------------------------\n";
223 return Standard_True;
7af17f1e
MA
224}
225
226//=======================================================================
227//function : LogFileHandler::Close
228//purpose :
229//=======================================================================
230
231void OSD_MAllocHook::LogFileHandler::Close()
232{
64531d9c 233 if (myLogFile.is_open())
7af17f1e 234 {
64531d9c 235 myLogFile.close();
7af17f1e
MA
236 }
237}
238
239//=======================================================================
240//function : LogFileHandler::MakeReport
241//purpose :
242//=======================================================================
243
244struct StorageInfo
245{
246 Standard_Size size;
247 int nbAlloc;
248 int nbFree;
249 int nbLeftPeak;
250 std::set<unsigned long>* alive;
251 StorageInfo()
252 : size(0), nbAlloc(0), nbFree(0), nbLeftPeak(0), alive(NULL) {}
253 StorageInfo(Standard_Size theSize)
254 : size(theSize), nbAlloc(0), nbFree(0), nbLeftPeak(0), alive(NULL) {}
255 ~StorageInfo()
256 {
257 if (alive)
258 delete alive;
259 }
260 std::set<unsigned long>& Alive()
261 {
262 if (!alive)
263 alive = new std::set<unsigned long>;
264 return *alive;
265 }
266 const std::set<unsigned long>& Alive() const
267 {
268 return *alive;
269 }
270};
271
272inline bool operator < (const StorageInfo& one, const StorageInfo& two)
273{
274 return one.size < two.size;
275}
276
277Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport
278 (const char* theLogFile,
279 const char* theOutFile,
280 const Standard_Boolean theIncludeAlive)
281{
282 // open log file
283 FILE* aLogFile = fopen(theLogFile, "r");
284 if (aLogFile == NULL)
285 return Standard_False;
286
287 // skip 2 header lines
288 char aStr[MAX_STR];
289 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
290 {
291 fclose(aLogFile);
292 return Standard_False;
293 }
294 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
295 {
296 fclose(aLogFile);
297 return Standard_False;
298 }
299
300 // scan the log file
301 size_t aTotalLeftSize = 0;
302 size_t aTotalPeakSize = 0;
303 std::set<StorageInfo> aStMap;
304 while (fgets(aStr, MAX_STR-1, aLogFile) != NULL)
305 {
306 // detect operation type, request number and block size
307 unsigned long aReqNum, aSize;
308 char* aType = aStr;
309 char* pStr = aStr;
310 //sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
311 while (*pStr != ' ' && *pStr) pStr++;
312 *pStr++ = '\0';
313 while (*pStr == ' ' && *pStr) pStr++;
314 aReqNum = atol(pStr);
315 while (*pStr != ' ' && *pStr) pStr++;
316 while (*pStr == ' ' && *pStr) pStr++;
317 aSize = atol(pStr);
318 Standard_Boolean isAlloc = Standard_False;
319 if (strcmp(aType, "alloc") == 0)
320 {
321 isAlloc = Standard_True;
322 }
323 else if (strcmp(aType, "free") != 0)
324 continue;
325
326 // collect statistics by storage size
327 StorageInfo aSuchInfo(aSize);
328 std::set<StorageInfo>::iterator aFound = aStMap.find(aSuchInfo);
329 if (aFound == aStMap.end())
330 aFound = aStMap.insert(aSuchInfo).first;
331 StorageInfo& aInfo = const_cast<StorageInfo&>(*aFound);
332 if (isAlloc)
333 {
334 if (aInfo.nbAlloc + 1 > 0)
335 aInfo.nbAlloc++;
336 aTotalLeftSize += aSize;
337 if (aTotalLeftSize > aTotalPeakSize)
338 aTotalPeakSize = aTotalLeftSize;
339 int nbLeft = aInfo.nbAlloc - aInfo.nbFree;
340 if (nbLeft > aInfo.nbLeftPeak)
341 aInfo.nbLeftPeak = nbLeft;
342 aInfo.Alive().insert(aReqNum);
343 }
344 else
345 {
346 std::set<unsigned long>::iterator aFoundReqNum =
347 aInfo.Alive().find(aReqNum);
348 if (aFoundReqNum == aInfo.Alive().end())
349 // freeing non-registered block, skip it
350 continue;
351 aTotalLeftSize -= aSize;
352 aInfo.Alive().erase(aFoundReqNum);
353 if (aInfo.nbAlloc + 1 > 0)
354 aInfo.nbFree++;
355 }
356 }
357 fclose(aLogFile);
358
359 // print the report
64531d9c 360 std::ofstream aRepFile (theOutFile);
361 if(!aRepFile.is_open())
362 {
7af17f1e 363 return Standard_False;
64531d9c 364 }
365 aRepFile.imbue (std::locale ("C"));
366
367 aRepFile << std::setw(20) << "BlockSize "
368 << std::setw(10) << "NbAlloc "
369 << std::setw(10) << "NbLeft "
370 << std::setw(10) << "NbLeftPeak "
371 << std::setw(20) << "AllocSize "
372 << std::setw(20) << "LeftSize "
373 << std::setw(20) << "PeakSize " << std::endl;
374
7af17f1e
MA
375 Standard_Size aTotAlloc = 0;
376 for (std::set<StorageInfo>::const_iterator it = aStMap.begin();
377 it != aStMap.end(); ++it)
378 {
379 const StorageInfo& aInfo = *it;
380 Standard_Integer nbLeft = aInfo.nbAlloc - aInfo.nbFree;
381 Standard_Size aSizeAlloc = aInfo.nbAlloc * aInfo.size;
382 Standard_Size aSizeLeft = nbLeft * aInfo.size;
383 Standard_Size aSizePeak = aInfo.nbLeftPeak * aInfo.size;
64531d9c 384
385 aRepFile << std::setw(20) << aInfo.size << ' '
386 << std::setw(10) << aInfo.nbAlloc << ' '
387 << std::setw(10) << nbLeft << ' '
388 << std::setw(10) << aInfo.nbLeftPeak << ' '
389 << std::setw(20) << aSizeAlloc << ' '
390 << std::setw(20) << aSizeLeft << ' '
391 << std::setw(20) << aSizePeak << std::endl;
392
7af17f1e
MA
393 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
394 aTotAlloc = SIZE_MAX;
395 else
396 aTotAlloc += aSizeAlloc;
397 if (theIncludeAlive && !aInfo.Alive().empty())
398 {
399 for (std::set<unsigned long>::const_iterator it1 = aInfo.alive->begin();
400 it1 != aInfo.alive->end(); ++it1)
64531d9c 401 aRepFile << std::setw(10) << *it1;
7af17f1e
MA
402 }
403 }
64531d9c 404 aRepFile << std::setw(20) << "Total:"
405 << std::setw(10) << "" << ' '
406 << std::setw(10) << "" << ' '
407 << std::setw(10) << "" << ' '
408 << (aTotAlloc == SIZE_MAX ? '>' : ' ')
409 << std::setw(20) << aTotAlloc << ' '
410 << std::setw(20) << aTotalLeftSize << ' '
411 << std::setw(20) << aTotalPeakSize << std::endl;
412
413 aRepFile.close();
7af17f1e
MA
414 return Standard_True;
415}
416
417//=======================================================================
418//function : LogFileHandler::AllocEvent
419//purpose :
420//=======================================================================
421
422void OSD_MAllocHook::LogFileHandler::AllocEvent
423 (size_t theSize,
424 long theRequestNum)
425{
64531d9c 426 if (myLogFile.is_open())
7af17f1e
MA
427 {
428 myMutex.Lock();
64531d9c 429 myLogFile << "alloc "<< std::setw(10) << theRequestNum
430 << std::setw(20) << theSize << std::endl;
7af17f1e 431 if (myBreakSize == theSize)
302f96fb 432 place_for_breakpoint();
433 myMutex.Unlock();
7af17f1e
MA
434 }
435}
436
437//=======================================================================
438//function : LogFileHandler::FreeEvent
439//purpose :
440//=======================================================================
441
442void OSD_MAllocHook::LogFileHandler::FreeEvent
443 (void* /*theData*/,
444 size_t theSize,
445 long theRequestNum)
446{
64531d9c 447 if (myLogFile.is_open())
7af17f1e
MA
448 {
449 myMutex.Lock();
64531d9c 450 myLogFile << "free " << std::setw(20) << theRequestNum
451 << std::setw(20) << theSize << std::endl;
7af17f1e
MA
452 myMutex.Unlock();
453 }
454}
455
456//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
457// CollectBySize handler methods
458//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
459
460//=======================================================================
461//function : CollectBySize::CollectBySize
462//purpose :
463//=======================================================================
464
465OSD_MAllocHook::CollectBySize::CollectBySize()
466: myArray(NULL),
467 myTotalLeftSize(0),
468 myTotalPeakSize(0),
941a7a24 469 myBreakSize(0),
470 myBreakPeak(0)
7af17f1e
MA
471{
472 Reset();
473}
474
475//=======================================================================
476//function : CollectBySize::~CollectBySize
477//purpose :
478//=======================================================================
479
480OSD_MAllocHook::CollectBySize::~CollectBySize()
481{
482 if (myArray != NULL)
483 delete [] myArray;
484}
485
486//=======================================================================
487//function : CollectBySize::Reset
488//purpose :
489//=======================================================================
490
491#define MAX_ALLOC_SIZE 2000000u
1cc1abe1 492const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
7af17f1e
MA
493
494void OSD_MAllocHook::CollectBySize::Reset()
495{
496 myMutex.Lock();
497 if (myArray == NULL)
498 myArray = new Numbers[MAX_ALLOC_SIZE];
499 else
500 {
501 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
502 myArray[i] = Numbers();
503 }
504 myTotalLeftSize = 0;
505 myTotalPeakSize = 0;
506 myMutex.Unlock();
507}
508
509//=======================================================================
510//function : CollectBySize::MakeReport
511//purpose :
512//=======================================================================
513
514Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
515{
516 // print the report
64531d9c 517 std::ofstream aRepFile(theOutFile);
518 if (!aRepFile.is_open())
7af17f1e 519 return Standard_False;
64531d9c 520 std::locale aCLoc("C");
521 aRepFile.imbue(aCLoc);
522
523 aRepFile << std::setw(10) << "BlockSize "
524 << std::setw(10) << "NbAlloc "
525 << std::setw(10) << "NbLeft "
526 << std::setw(10) << "NbLeftPeak "
527 << std::setw(20) << "AllocSize "
528 << std::setw(20) << "LeftSize "
529 << std::setw(20) << "PeakSize " << std::endl;
530
7af17f1e
MA
531 Standard_Size aTotAlloc = 0;
532 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
533 {
13b4230b 534 if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
7af17f1e
MA
535 {
536 Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
7af17f1e
MA
537 int aSize = i + 1;
538 Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
13b4230b 539 ptrdiff_t aSizeLeft = nbLeft * aSize;
7af17f1e 540 Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
64531d9c 541
542 aRepFile << std::setw(10) << aSize << ' '
543 << std::setw(10) << myArray[i].nbAlloc << ' '
544 << std::setw(10) << nbLeft << ' '
545 << std::setw(10) << myArray[i].nbLeftPeak << ' '
546 << std::setw(20) << aSizeAlloc << ' '
547 << std::setw(20) << aSizeLeft << ' '
548 << std::setw(20) << aSizePeak << std::endl;
549
7af17f1e
MA
550 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
551 aTotAlloc = SIZE_MAX;
552 else
553 aTotAlloc += aSizeAlloc;
554 }
555 }
64531d9c 556 aRepFile << std::setw(10) << "Total:" << ' '
557 << std::setw(10) << "" << ' '
558 << std::setw(10) << "" << ' '
559 << std::setw(10) << "" << ' '
560 << (aTotAlloc == SIZE_MAX ? '>' : ' ')
561 << std::setw(20) << aTotAlloc << ' '
562 << std::setw(20) << myTotalLeftSize << ' '
563 << std::setw(20) << myTotalPeakSize << std::endl;
564 aRepFile.close();
7af17f1e
MA
565 return Standard_True;
566}
567
568//=======================================================================
569//function : CollectBySize::AllocEvent
570//purpose :
571//=======================================================================
572
573void OSD_MAllocHook::CollectBySize::AllocEvent
574 (size_t theSize,
575 long /*theRequestNum*/)
576{
577 if (myBreakSize == theSize)
302f96fb 578 place_for_breakpoint();
7af17f1e
MA
579 if (theSize > 0)
580 {
581 myMutex.Lock();
582 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
13b4230b 583 myArray[ind].nbAlloc++;
7af17f1e
MA
584 myTotalLeftSize += theSize;
585 int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
586 if (nbLeft > myArray[ind].nbLeftPeak)
941a7a24 587 {
7af17f1e 588 myArray[ind].nbLeftPeak = nbLeft;
941a7a24 589 if (myBreakPeak != 0
590 && (myBreakSize == theSize || myBreakSize == 0))
591 {
592 const Standard_Size aSizePeak = myArray[ind].nbLeftPeak * theSize;
593 if (aSizePeak > myBreakPeak)
594 {
595 place_for_breakpoint();
596 }
597 }
598 }
13b4230b 599 if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
7af17f1e
MA
600 myTotalPeakSize = myTotalLeftSize;
601 myMutex.Unlock();
602 }
603}
604
605//=======================================================================
606//function : CollectBySize::FreeEvent
607//purpose :
608//=======================================================================
609
610void OSD_MAllocHook::CollectBySize::FreeEvent
611 (void* /*theData*/,
612 size_t theSize,
613 long /*theRequestNum*/)
614{
13b4230b 615 if (theSize > 0)
7af17f1e
MA
616 {
617 myMutex.Lock();
618 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
13b4230b 619 myArray[ind].nbFree++;
7af17f1e
MA
620 myTotalLeftSize -= theSize;
621 myMutex.Unlock();
622 }
623}