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