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