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