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