Logo ROOT  
Reference Guide
TMemStatMng.cxx
Go to the documentation of this file.
1// @(#)root/memstat:$Id$
2// Author: Anar Manafov (A.Manafov@gsi.de) 2008-03-02
3
4/*************************************************************************
5* Copyright (C) 1995-2010, Rene Brun and Fons Rademakers. *
6* All rights reserved. *
7* *
8* For the licensing terms see $ROOTSYS/LICENSE. *
9* For the list of contributors see $ROOTSYS/README/CREDITS. *
10*************************************************************************/
11// STD
12#include <cstdlib>
13// ROOT
14#include "TSystem.h"
15#include "TEnv.h"
16#include "TError.h"
17#include "Riostream.h"
18#include "TObject.h"
19#include "TFile.h"
20#include "TTree.h"
21#include "TArrayL64.h"
22#include "TH1.h"
23#include "TMD5.h"
24#include "TMath.h"
25// Memstat
26#include "TMemStatBacktrace.h"
27#include "TMemStatMng.h"
28
29using namespace Memstat;
30
32
33TMemStatMng* TMemStatMng::fgInstance = NULL;
34
35//****************************************************************************//
36//
37//****************************************************************************//
38
39TMemStatMng::TMemStatMng():
40 TObject(),
41#if !defined(__APPLE__)
42 fPreviousMallocHook(TMemStatHook::GetMallocHook()),
43 fPreviousFreeHook(TMemStatHook::GetFreeHook()),
44#endif
45 fDumpFile(NULL),
46 fDumpTree(NULL),
47 fUseGNUBuiltinBacktrace(kFALSE),
48 fBeginTime(0),
49 fPos(0),
50 fTimems(0),
51 fNBytes(0),
52 fBtID(0),
53 fMaxCalls(5000000),
54 fBufferSize(10000),
55 fBufN(0),
56 fBufPos(0),
57 fBufTimems(0),
58 fBufNBytes(0),
59 fBufBtID(0),
60 fIndex(0),
61 fMustWrite(0),
62 fFAddrsList(0),
63 fHbtids(0),
64 fBTCount(0),
65 fBTIDCount(0),
66 fSysInfo(0)
67{
68 // Default constructor
69}
70
71////////////////////////////////////////////////////////////////////////////////
72///Initialize MemStat manager - used only by instance method
73
75{
77
78 fDumpFile = new TFile(Form("memstat_%d.root", gSystem->GetPid()), "recreate");
79 Int_t opt = 200000;
80 if(!fDumpTree) {
81 fDumpTree = new TTree("T", "Memory Statistics");
82 fDumpTree->Branch("pos", &fPos, "pos/l", opt);
83 fDumpTree->Branch("time", &fTimems, "time/I", opt);
84 fDumpTree->Branch("nbytes", &fNBytes, "nbytes/I", opt);
85 fDumpTree->Branch("btid", &fBtID, "btid/I", opt);
86 }
87
88 fBTCount = 0;
89
90 fBTIDCount = 0;
91
92 fFAddrsList = new TObjArray();
94 fFAddrsList->SetName("FAddrsList");
95
96 fHbtids = new TH1I("btids", "table of btids", 10000, 0, 1); //where fHbtids is a member of the manager class
98 // save the histogram and the TObjArray to the tree header
101 // save the system info to a tree header
102 std::string sSysInfo(gSystem->GetBuildNode());
103 sSysInfo += " | ";
104 sSysInfo += gSystem->GetBuildCompilerVersion();
105 sSysInfo += " | ";
106 sSysInfo += gSystem->GetFlagsDebug();
107 sSysInfo += " ";
108 sSysInfo += gSystem->GetFlagsOpt();
109 fSysInfo = new TNamed("SysInfo", sSysInfo.c_str());
110
112 fDumpTree->SetAutoSave(10000000);
113}
114
115////////////////////////////////////////////////////////////////////////////////
116/// GetInstance - a static function
117/// Initialize a singleton of MemStat manager
118
120{
121 if(!fgInstance) {
123 fgInstance->Init();
124 }
125 return fgInstance;
126}
127
128////////////////////////////////////////////////////////////////////////////////
129/// Close - a static function
130/// This method stops the manager,
131/// flashes all the buffered data and closes the output tree.
132
134{
135 // TODO: This is a temporary solution until we find a properalgorithm for SaveData
136 //fgInstance->fDumpFile->WriteObject(fgInstance->fFAddrsList, "FAddrsList");
137
138/* std::ofstream f("mem_stat_debug.txt");
139 int *btids = fgInstance->fHbtids->GetArray();
140 if( !btids )
141 return;
142 int btid(1);
143 int count(0);
144 bool bStop(false);
145 int count_empty(0);
146 for (int i = 0; i < fgInstance->fBTChecksums.size(); ++i)
147 {
148 if (bStop)
149 break;
150 count = btids[btid-1];
151 f << "++++++++++++++++++++++++\n";
152 f << "BTID: " << btid << "\n";
153 if ( count <= 0 )
154 ++count_empty;
155 for (int j = btid+1; j <= (btid+count); ++j )
156 {
157 TNamed *nm = (TNamed*)fgInstance->fFAddrsList->At(btids[j]);
158 if( !nm )
159 {
160 f << "Bad ID" << std::endl;
161 bStop = true;
162 }
163 f << "-------> " << nm->GetTitle() << "\n";
164 }
165 btid = btid + count + 1;
166 }
167 f.close();
168 ::Info("TMemStatMng::Close", "btids without a stack %d\n", count_empty);
169*/
170
171 // to be documented
176
177 ::Info("TMemStatMng::Close", "Tree saved to file %s\n", fgInstance->fDumpFile->GetName());
178 ::Info("TMemStatMng::Close", "Tree entries = %d, file size = %g MBytes\n", (Int_t)fgInstance->fDumpTree->GetEntries(),1e-6*Double_t(fgInstance->fDumpFile->GetEND()));
179
180 delete fgInstance->fDumpFile;
181 //fgInstance->fDumpFile->Close();
182 //delete fgInstance->fFAddrsList;
183 //delete fgInstance->fSysInfo;
184
185 delete fgInstance;
186 fgInstance = NULL;
187}
188
189////////////////////////////////////////////////////////////////////////////////
190/// if an instance is destructed - the hooks are reseted to old hooks
191
193{
194 if(this != TMemStatMng::GetInstance())
195 return;
196
197 Info("~TMemStatMng", ">>> All free/malloc calls count: %d", fBTIDCount);
198 Info("~TMemStatMng", ">>> Unique BTIDs count: %zu", fBTChecksums.size());
199
200 Disable();
201}
202
203////////////////////////////////////////////////////////////////////////////////
204/// Set the maximum number of alloc/free calls to be buffered.
205///if the alloc and free are in the buffer, the corresponding entries
206///are not saved tio the Tree, reducing considerably the Tree output size
207
209{
210 fBufferSize = buffersize;
211 if (fBufferSize < 1) fBufferSize = 1;
212 fBufN = 0;
217 fIndex = new Int_t[fBufferSize];
219}
220
221////////////////////////////////////////////////////////////////////////////////
222/// Set the maximum number of new/delete registered in the output Tree.
223
225{
226 fMaxCalls = maxcalls;
227}
228
229////////////////////////////////////////////////////////////////////////////////
230/// Enable memory hooks
231
233{
234 if(this != GetInstance())
235 return;
236#if defined(__APPLE__)
237 TMemStatHook::trackZoneMalloc(MacAllocHook, MacFreeHook);
238#else
239 // set hook to our functions
242#endif
243}
244
245////////////////////////////////////////////////////////////////////////////////
246/// Disble memory hooks
247
249{
250 //FillTree();
251 if(this != GetInstance())
252 return;
253#if defined(__APPLE__)
254 TMemStatHook::untrackZoneMalloc();
255#else
256 // set hook to our functions
259#endif
260}
261
262////////////////////////////////////////////////////////////////////////////////
263/// AllocHook - a static function
264/// a special memory hook for Mac OS X memory zones.
265/// Triggered when memory is allocated.
266
267void TMemStatMng::MacAllocHook(void *ptr, size_t size)
268{
270 // Restore all old hooks
271 instance->Disable();
272
273 // Call our routine
274 instance->AddPointer(ptr, Int_t(size));
275
276 // Restore our own hooks
277 instance->Enable();
278}
279
280////////////////////////////////////////////////////////////////////////////////
281/// AllocHook - a static function
282/// a special memory hook for Mac OS X memory zones.
283/// Triggered when memory is deallocated.
284
286{
288 // Restore all old hooks
289 instance->Disable();
290
291 // Call our routine
292 instance->AddPointer(ptr, -1);
293
294 // Restore our own hooks
295 instance->Enable();
296}
297
298////////////////////////////////////////////////////////////////////////////////
299/// AllocHook - a static function
300/// A glibc memory allocation hook.
301
302void *TMemStatMng::AllocHook(size_t size, const void* /*caller*/)
303{
305 // Restore all old hooks
306 instance->Disable();
307
308 // Call recursively
309 void *result = malloc(size);
310 // Call our routine
311 instance->AddPointer(result, Int_t(size));
312 // TTimer::SingleShot(0, "TYamsMemMng", instance, "SaveData()");
313
314 // Restore our own hooks
315 instance->Enable();
316
317 return result;
318}
319
320////////////////////////////////////////////////////////////////////////////////
321/// FreeHook - a static function
322/// A glibc memory deallocation hook.
323
324void TMemStatMng::FreeHook(void* ptr, const void* /*caller*/)
325{
327 // Restore all old hooks
328 instance->Disable();
329
330 // Call recursively
331 free(ptr);
332
333 // Call our routine
334 instance->AddPointer(ptr, -1);
335
336 // Restore our own hooks
337 instance->Enable();
338}
339
340////////////////////////////////////////////////////////////////////////////////
341/// An internal function, which returns a bitid for a corresponding CRC digest
342/// cache variables
343
345 void **stackPointers)
346{
347 static Int_t old_btid = -1;
348 static SCustomDigest old_digest;
349
350 Int_t ret_val = -1;
351 bool startCheck(false);
352 if(old_btid >= 0) {
353 for(int i = 0; i < g_digestSize; ++i) {
354 if(old_digest.fValue[i] != CRCdigest[i]) {
355 startCheck = true;
356 break;
357 }
358 }
359 ret_val = old_btid;
360 } else {
361 startCheck = true;
362 }
363
364 // return cached value
365 if(!startCheck)
366 return ret_val;
367
368 old_digest = SCustomDigest(CRCdigest);
369 CRCSet_t::const_iterator found = fBTChecksums.find(CRCdigest);
370
371 if(fBTChecksums.end() == found) {
372 // check the size of the BT array container
373 const int nbins = fHbtids->GetNbinsX();
374 //check that the current allocation in fHbtids is enough, otherwise expend it with
375 if(fBTCount + stackEntries + 1 >= nbins) {
376 fHbtids->SetBins(nbins * 2, 0, 1);
377 }
378
379 int *btids = fHbtids->GetArray();
380 // the first value is a number of entries in a given stack
381 btids[fBTCount++] = stackEntries;
382 ret_val = fBTCount;
383 if(stackEntries <= 0) {
384 Warning("AddPointer",
385 "A number of stack entries is equal or less than zero. For btid %d", ret_val);
386 }
387
388 // add new BT's CRC value
389 std::pair<CRCSet_t::iterator, bool> res = fBTChecksums.insert(CRCSet_t::value_type(CRCdigest, ret_val));
390 if(!res.second)
391 Error("AddPointer", "Can't added a new BTID to the container.");
392
393 // save all symbols of this BT
394 for(int i = 0; i < stackEntries; ++i) {
395 ULong_t func_addr = (ULong_t)(stackPointers[i]);
396 Int_t idx = fFAddrs.find(func_addr);
397 // check, whether it's a new symbol
398 if(idx < 0) {
399 TString strFuncAddr;
400 strFuncAddr += func_addr;
401 TString strSymbolInfo;
402 getSymbolFullInfo(stackPointers[i], &strSymbolInfo);
403
404 TNamed *nm = new TNamed(strFuncAddr, strSymbolInfo);
406 idx = fFAddrsList->GetEntriesFast() - 1;
407 // TODO: more detailed error message...
408 if(!fFAddrs.add(func_addr, idx))
409 Error("AddPointer", "Can't add a function return address to the container");
410 }
411
412 // even if we have -1 as an index we add it to the container
413 btids[fBTCount++] = idx;
414 }
415
416 } else {
417 // reuse an existing BT
418 ret_val = found->second;
419 }
420
421 old_btid = ret_val;
422
423 return ret_val;
424}
425
426////////////////////////////////////////////////////////////////////////////////
427/// Add pointer to table.
428/// This method is called every time when any of the hooks are triggered.
429/// The memory de-/allocation information will is recorded.
430
431void TMemStatMng::AddPointer(void *ptr, Int_t size)
432{
433 void *stptr[g_BTStackLevel + 1];
434 const int stackentries = getBacktrace(stptr, g_BTStackLevel, fUseGNUBuiltinBacktrace);
435
436 // save only unique BTs
437 TMD5 md5;
438 md5.Update(reinterpret_cast<UChar_t*>(stptr), sizeof(void*) * stackentries);
439 UChar_t digest[g_digestSize];
440 md5.Final(digest);
441
442 // for Debug. A counter of all (de)allacations.
443 ++fBTIDCount;
444
445 Int_t btid(generateBTID(digest, stackentries, stptr));
446
447 if(btid <= 0)
448 Error("AddPointer", "bad BT id");
449
450 fTimeStamp.Set();
451 Double_t CurTime = fTimeStamp.AsDouble();
452 fBufTimems[fBufN] = Int_t(10000.*(CurTime - fBeginTime));
453 ULong_t ul = (ULong_t)(ptr);
454 fBufPos[fBufN] = (ULong64_t)(ul);
455 fBufNBytes[fBufN] = size;
456 fBufBtID[fBufN] = btid;
457 fBufN++;
458 if (fBufN >= fBufferSize) {
459 FillTree();
460 }
461}
462
463////////////////////////////////////////////////////////////////////////////////
464///loop on all entries in the buffer and fill the output Tree
465///entries with alloc and free in the buffer are eliminated
466
468{
469
470 //eliminate alloc/free pointing to the same location in the current buffer
472 memset(fMustWrite,0,fBufN*sizeof(Bool_t));
473 Int_t i=0,j;
474 while (i<fBufN) {
475 Int_t indi = fIndex[i];
476 Int_t indmin = indi;
477 Int_t indmax = indi;
478 j = i+1;;
479 ULong64_t pos = fBufPos[indi];
480 while (j < fBufN) {
481 Int_t indj = fIndex[j];
482 ULong64_t posj = fBufPos[indj];
483 if (posj != pos) break;
484 if (indmin > indj) indmin = indj;
485 if (indmax < indj) indmax = indj;
486 j++;
487 }
488 if (indmin == indmax) fMustWrite[indmin] = kTRUE;
489 if (fBufNBytes[indmin] == -1) fMustWrite[indmin] = kTRUE;
490 if (fBufNBytes[indmax] > 0) fMustWrite[indmax] = kTRUE;
491 i = j;
492 }
493
494 // now fill the Tree with the remaining allocs/frees
495 for (i=0;i<fBufN;i++) {
496 if (!fMustWrite[i]) continue;
497 fPos = fBufPos[i];
498 fTimems = fBufTimems[i];
499 fNBytes = fBufNBytes[i];
500 fBtID = fBufBtID[i];
501 fDumpTree->Fill();
502 }
503
504 fBufN = 0;
506}
#define e(i)
Definition: RSha256.hxx:103
int Int_t
Definition: RtypesCore.h:41
unsigned char UChar_t
Definition: RtypesCore.h:34
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
bool Bool_t
Definition: RtypesCore.h:59
double Double_t
Definition: RtypesCore.h:55
unsigned long long ULong64_t
Definition: RtypesCore.h:70
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define ClassImp(name)
Definition: Rtypes.h:365
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
Definition: TSystem.h:560
#define free
Definition: civetweb.c:1539
#define malloc
Definition: civetweb.c:1536
Int_t find(ULong_t addr)
Definition: TMemStatMng.h:41
bool add(ULong_t addr, Int_t idx)
Definition: TMemStatMng.h:36
Bool_t fUseGNUBuiltinBacktrace
Definition: TMemStatMng.h:117
Int_t generateBTID(UChar_t *CRCdigest, Int_t stackEntries, void **stackPointers)
An internal function, which returns a bitid for a corresponding CRC digest cache variables.
static void MacAllocHook(void *ptr, size_t size)
AllocHook - a static function a special memory hook for Mac OS X memory zones.
TMemStatHook::FreeHookFunc_t fPreviousFreeHook
old malloc function
Definition: TMemStatMng.h:98
static void FreeHook(void *ptr, const void *)
FreeHook - a static function A glibc memory deallocation hook.
static void MacFreeHook(void *ptr)
AllocHook - a static function a special memory hook for Mac OS X memory zones.
static TMemStatMng * fgInstance
tree to dump information
Definition: TMemStatMng.h:114
void Disable()
Disble memory hooks.
TObjArray * fFAddrsList
Definition: TMemStatMng.h:136
TMemStatFAddrContainer fFAddrs
Definition: TMemStatMng.h:135
static void * AllocHook(size_t size, const void *)
AllocHook - a static function A glibc memory allocation hook.
TTree * fDumpTree
file to dump current information
Definition: TMemStatMng.h:113
virtual ~TMemStatMng()
if an instance is destructed - the hooks are reseted to old hooks
void Init()
old free function
Definition: TMemStatMng.cxx:74
TTimeStamp fTimeStamp
Definition: TMemStatMng.h:118
ULong64_t * fBufPos
Definition: TMemStatMng.h:127
void Enable()
Enable memory hooks.
void SetBufferSize(Int_t buffersize)
Set the maximum number of alloc/free calls to be buffered.
TMemStatHook::MallocHookFunc_t fPreviousMallocHook
Definition: TMemStatMng.h:97
void AddPointer(void *ptr, Int_t size)
Add pointer to table.
static void Close()
Close - a static function This method stops the manager, flashes all the buffered data and closes the...
void SetMaxCalls(Int_t maxcalls)
Set the maximum number of new/delete registered in the output Tree.
void FillTree()
loop on all entries in the buffer and fill the output Tree entries with alloc and free in the buffer ...
static TMemStatMng * GetInstance()
GetInstance - a static function Initialize a singleton of MemStat manager.
const Int_t * GetArray() const
Definition: TArrayI.h:43
void SetName(const char *name)
Definition: TCollection.h:204
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:48
virtual Long64_t GetEND() const
Definition: TFile.h:218
1-D histogram with an int per channel (see TH1 documentation)}
Definition: TH1.h:530
virtual void SetDirectory(TDirectory *dir)
By default when an histogram is created, it is added to the list of histogram objects in the current ...
Definition: TH1.cxx:8381
virtual Int_t GetNbinsX() const
Definition: TH1.h:292
virtual void SetBins(Int_t nx, Double_t xmin, Double_t xmax)
Redefine x axis parameters.
Definition: TH1.cxx:8211
virtual void Add(TObject *obj)
Definition: TList.h:87
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
This code implements the MD5 message-digest algorithm.
Definition: TMD5.h:44
void Update(const UChar_t *buf, UInt_t len)
Update TMD5 object to reflect the concatenation of another buffer full of bytes.
Definition: TMD5.cxx:108
void Final()
MD5 finalization, ends an MD5 message-digest operation, writing the the message digest and zeroizing ...
Definition: TMD5.cxx:167
static void SetMallocHook(MallocHookFunc_t p)
SetMallocHook - a static function Set pointer to function replacing alloc function.
static void SetFreeHook(FreeHookFunc_t p)
SetFreeHook - a static function Set pointer to function replacing free function.
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:29
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t GetEntriesFast() const
Definition: TObjArray.h:64
void Add(TObject *obj)
Definition: TObjArray.h:74
Mother of all ROOT objects.
Definition: TObject.h:37
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
Basic string class.
Definition: TString.h:131
virtual const char * GetBuildNode() const
Return the build node name.
Definition: TSystem.cxx:3889
virtual const char * GetBuildCompilerVersion() const
Return the build compiler version.
Definition: TSystem.cxx:3881
virtual int GetPid()
Get process id.
Definition: TSystem.cxx:717
virtual const char * GetFlagsDebug() const
Return the debug flags.
Definition: TSystem.cxx:3909
virtual const char * GetFlagsOpt() const
Return the optimization flags.
Definition: TSystem.cxx:3917
void Set()
Set Date/Time to current time as reported by the system.
Definition: TTimeStamp.cxx:556
Double_t AsDouble() const
Definition: TTimeStamp.h:138
A TTree represents a columnar dataset.
Definition: TTree.h:72
virtual Int_t Fill()
Fill all branches.
Definition: TTree.cxx:4487
virtual void SetAutoSave(Long64_t autos=-300000000)
This function may be called at the start of a program to change the default value for fAutoSave (and ...
Definition: TTree.cxx:8084
virtual Long64_t GetEntries() const
Definition: TTree.h:450
virtual Long64_t AutoSave(Option_t *option="")
AutoSave tree header every fAutoSave bytes.
Definition: TTree.cxx:1467
TBranch * Branch(const char *name, T *obj, Int_t bufsize=32000, Int_t splitlevel=99)
Add a new branch, and infer the data type from the type of obj being passed.
Definition: TTree.h:341
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition: TTree.cxx:6212
const UShort_t g_digestSize
Definition: TMemStatMng.h:53
void getSymbolFullInfo(void *_pAddr, TString *_retInfo, const char *const _seporator=" | ")
size_t getBacktrace(void **_trace, size_t _size, Bool_t _bUseGNUBuiltinBacktrace=kFALSE)
Get the backtrace _trace - array of pointers _size - maximal deepness of stack information _bUseGNUBu...
const size_t g_BTStackLevel
Definition: TMemStatDef.h:17
static Roo_reg_AGKInteg1D instance
static constexpr double nm
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Definition: TMathBase.h:362
UChar_t fValue[g_digestSize]
Definition: TMemStatMng.h:62