0023625: New functionality building reflect lines on a shape
[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
21#include <OSD_MAllocHook.hxx>
22
23#ifndef WNT
24#if !defined __STDC_LIMIT_MACROS
25#define __STDC_LIMIT_MACROS
26#endif
27#include <stdint.h>
28#endif
29
30#include <set>
31#include <map>
e2f8b392 32#include <cstdlib>
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()
178: myLogFile(NULL),
179 myBreakSize(0)
180{
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();
201 myLogFile = fopen(theFileName, "w");
202 if (myLogFile != NULL)
203 {
204 fputs("Operation type; Request Number; Block Size\n", myLogFile);
205 fputs("------------------------------------------\n", myLogFile);
206 }
207 return myLogFile != NULL;
208}
209
210//=======================================================================
211//function : LogFileHandler::Close
212//purpose :
213//=======================================================================
214
215void OSD_MAllocHook::LogFileHandler::Close()
216{
217 if (myLogFile != NULL)
218 {
219 fclose(myLogFile);
220 myLogFile = NULL;
221 }
222}
223
224//=======================================================================
225//function : LogFileHandler::MakeReport
226//purpose :
227//=======================================================================
228
229struct StorageInfo
230{
231 Standard_Size size;
232 int nbAlloc;
233 int nbFree;
234 int nbLeftPeak;
235 std::set<unsigned long>* alive;
236 StorageInfo()
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) {}
240 ~StorageInfo()
241 {
242 if (alive)
243 delete alive;
244 }
245 std::set<unsigned long>& Alive()
246 {
247 if (!alive)
248 alive = new std::set<unsigned long>;
249 return *alive;
250 }
251 const std::set<unsigned long>& Alive() const
252 {
253 return *alive;
254 }
255};
256
257inline bool operator < (const StorageInfo& one, const StorageInfo& two)
258{
259 return one.size < two.size;
260}
261
262Standard_Boolean OSD_MAllocHook::LogFileHandler::MakeReport
263 (const char* theLogFile,
264 const char* theOutFile,
265 const Standard_Boolean theIncludeAlive)
266{
267 // open log file
268 FILE* aLogFile = fopen(theLogFile, "r");
269 if (aLogFile == NULL)
270 return Standard_False;
271
272 // skip 2 header lines
273 char aStr[MAX_STR];
274 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
275 {
276 fclose(aLogFile);
277 return Standard_False;
278 }
279 if (fgets(aStr, MAX_STR-1, aLogFile) == NULL)
280 {
281 fclose(aLogFile);
282 return Standard_False;
283 }
284
285 // scan the log file
286 size_t aTotalLeftSize = 0;
287 size_t aTotalPeakSize = 0;
288 std::set<StorageInfo> aStMap;
289 while (fgets(aStr, MAX_STR-1, aLogFile) != NULL)
290 {
291 // detect operation type, request number and block size
292 unsigned long aReqNum, aSize;
293 char* aType = aStr;
294 char* pStr = aStr;
295 //sscanf(aStr, "%5s %lu %lu", aType, &aReqNum, &aSize);
296 while (*pStr != ' ' && *pStr) pStr++;
297 *pStr++ = '\0';
298 while (*pStr == ' ' && *pStr) pStr++;
299 aReqNum = atol(pStr);
300 while (*pStr != ' ' && *pStr) pStr++;
301 while (*pStr == ' ' && *pStr) pStr++;
302 aSize = atol(pStr);
303 Standard_Boolean isAlloc = Standard_False;
304 if (strcmp(aType, "alloc") == 0)
305 {
306 isAlloc = Standard_True;
307 }
308 else if (strcmp(aType, "free") != 0)
309 continue;
310
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);
317 if (isAlloc)
318 {
319 if (aInfo.nbAlloc + 1 > 0)
320 aInfo.nbAlloc++;
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);
328 }
329 else
330 {
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
335 continue;
336 aTotalLeftSize -= aSize;
337 aInfo.Alive().erase(aFoundReqNum);
338 if (aInfo.nbAlloc + 1 > 0)
339 aInfo.nbFree++;
340 }
341 }
342 fclose(aLogFile);
343
344 // print the report
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)
354 {
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;
365 else
366 aTotAlloc += aSizeAlloc;
367 if (theIncludeAlive && !aInfo.Alive().empty())
368 {
369 for (std::set<unsigned long>::const_iterator it1 = aInfo.alive->begin();
370 it1 != aInfo.alive->end(); ++it1)
371 fprintf(aRepFile, "%10lu\n", *it1);
372 }
373 }
374 fprintf(aRepFile, "%10s %10s %10s %10s%c%10Iu %10Iu %10Iu\n", "Total:",
375 "", "", "", (aTotAlloc == SIZE_MAX ? '>' : ' '), aTotAlloc,
376 aTotalLeftSize, aTotalPeakSize);
377 fclose(aRepFile);
378 return Standard_True;
379}
380
381//=======================================================================
382//function : LogFileHandler::AllocEvent
383//purpose :
384//=======================================================================
385
386void OSD_MAllocHook::LogFileHandler::AllocEvent
387 (size_t theSize,
388 long theRequestNum)
389{
390 if (myLogFile != NULL)
391 {
392 myMutex.Lock();
393 fprintf(myLogFile, "alloc %10lu %10u\n", theRequestNum, theSize);
394 myMutex.Unlock();
395 if (myBreakSize == theSize)
396 {
397 int a = 1;
398 }
399 }
400}
401
402//=======================================================================
403//function : LogFileHandler::FreeEvent
404//purpose :
405//=======================================================================
406
407void OSD_MAllocHook::LogFileHandler::FreeEvent
408 (void* /*theData*/,
409 size_t theSize,
410 long theRequestNum)
411{
412 if (myLogFile != NULL)
413 {
414 myMutex.Lock();
415 fprintf(myLogFile, "free %10lu %10u\n", theRequestNum, theSize);
416 myMutex.Unlock();
417 }
418}
419
420//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
421// CollectBySize handler methods
422//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
423
424//=======================================================================
425//function : CollectBySize::CollectBySize
426//purpose :
427//=======================================================================
428
429OSD_MAllocHook::CollectBySize::CollectBySize()
430: myArray(NULL),
431 myTotalLeftSize(0),
432 myTotalPeakSize(0),
433 myBreakSize(0)
434{
435 Reset();
436}
437
438//=======================================================================
439//function : CollectBySize::~CollectBySize
440//purpose :
441//=======================================================================
442
443OSD_MAllocHook::CollectBySize::~CollectBySize()
444{
445 if (myArray != NULL)
446 delete [] myArray;
447}
448
449//=======================================================================
450//function : CollectBySize::Reset
451//purpose :
452//=======================================================================
453
454#define MAX_ALLOC_SIZE 2000000u
1cc1abe1 455const size_t OSD_MAllocHook::CollectBySize::myMaxAllocSize = MAX_ALLOC_SIZE;
7af17f1e
MA
456
457void OSD_MAllocHook::CollectBySize::Reset()
458{
459 myMutex.Lock();
460 if (myArray == NULL)
461 myArray = new Numbers[MAX_ALLOC_SIZE];
462 else
463 {
464 for (int i = 0; i < MAX_ALLOC_SIZE; i++)
465 myArray[i] = Numbers();
466 }
467 myTotalLeftSize = 0;
468 myTotalPeakSize = 0;
469 myMutex.Unlock();
470}
471
472//=======================================================================
473//function : CollectBySize::MakeReport
474//purpose :
475//=======================================================================
476
477Standard_Boolean OSD_MAllocHook::CollectBySize::MakeReport(const char* theOutFile)
478{
479 // print the report
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++)
488 {
13b4230b 489 if (myArray[i].nbAlloc > 0 || myArray[i].nbFree > 0)
7af17f1e
MA
490 {
491 Standard_Integer nbLeft = myArray[i].nbAlloc - myArray[i].nbFree;
7af17f1e
MA
492 int aSize = i + 1;
493 Standard_Size aSizeAlloc = myArray[i].nbAlloc * aSize;
13b4230b 494 ptrdiff_t aSizeLeft = nbLeft * aSize;
7af17f1e 495 Standard_Size aSizePeak = myArray[i].nbLeftPeak * aSize;
13b4230b 496 fprintf(aRepFile, "%10d %10d %10d %10d %10Iu %10Id %10Iu\n", aSize,
7af17f1e
MA
497 myArray[i].nbAlloc, nbLeft, myArray[i].nbLeftPeak,
498 aSizeAlloc, aSizeLeft, aSizePeak);
499 if (aTotAlloc + aSizeAlloc < aTotAlloc) // overflow ?
500 aTotAlloc = SIZE_MAX;
501 else
502 aTotAlloc += aSizeAlloc;
503 }
504 }
13b4230b 505 fprintf(aRepFile, "%10s %10s %10s %10s%c%10Iu %10Id %10Iu\n", "Total:",
7af17f1e
MA
506 "", "", "", (aTotAlloc == SIZE_MAX ? '>' : ' '), aTotAlloc,
507 myTotalLeftSize, myTotalPeakSize);
508 fclose(aRepFile);
509 return Standard_True;
510}
511
512//=======================================================================
513//function : CollectBySize::AllocEvent
514//purpose :
515//=======================================================================
516
517void OSD_MAllocHook::CollectBySize::AllocEvent
518 (size_t theSize,
519 long /*theRequestNum*/)
520{
521 if (myBreakSize == theSize)
522 {
523 int a = 1;
524 }
525 if (theSize > 0)
526 {
527 myMutex.Lock();
528 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
13b4230b 529 myArray[ind].nbAlloc++;
7af17f1e
MA
530 myTotalLeftSize += theSize;
531 int nbLeft = myArray[ind].nbAlloc - myArray[ind].nbFree;
532 if (nbLeft > myArray[ind].nbLeftPeak)
533 myArray[ind].nbLeftPeak = nbLeft;
13b4230b 534 if (myTotalLeftSize > (ptrdiff_t)myTotalPeakSize)
7af17f1e
MA
535 myTotalPeakSize = myTotalLeftSize;
536 myMutex.Unlock();
537 }
538}
539
540//=======================================================================
541//function : CollectBySize::FreeEvent
542//purpose :
543//=======================================================================
544
545void OSD_MAllocHook::CollectBySize::FreeEvent
546 (void* /*theData*/,
547 size_t theSize,
548 long /*theRequestNum*/)
549{
13b4230b 550 if (theSize > 0)
7af17f1e
MA
551 {
552 myMutex.Lock();
553 int ind = (theSize > MAX_ALLOC_SIZE ? MAX_ALLOC_SIZE-1 : (int)(theSize-1));
13b4230b 554 myArray[ind].nbFree++;
7af17f1e
MA
555 myTotalLeftSize -= theSize;
556 myMutex.Unlock();
557 }
558}