From b0e78e76da59cc43a225b9db38b97a1b19a7e732 Mon Sep 17 00:00:00 2001 From: Rene Brun <Rene.Brun@cern.ch> Date: Wed, 18 Jun 2008 14:03:58 +0000 Subject: [PATCH] From Marian Ivanov and Anar Manafov: Introduce a new package memstat for visualization of the memory usage. This package is expected to evolve in the coming hours/days. Principle: Hook functions for alloc and free are used. All calls to alloc (new) and free (delete) are catched and the statistical information is collected. The information is collected per stack trace (Unique identifier and per functions). Following informations are collected as function of time: Total number of allocations Total allocation size Allocation count Allocation size How to use it: Create memstat object TMemStat memstat(autoStamSize=10000, autoStampCount=1000); autoStamSize - The increase - decrease of size of memory after which stamps are generated autoStampCount - The increase - decrease of memory allocation counter after which stamps are generated User request for adding the named memory stamp is supported. memstat.AddStamp("mystamp") The file "memstat.root" is created after destruction of object. This class supports following functions for standard user: constructor - TMemStat memstat(filename) Report Draw SelectCode(libname, functionname) SelectStack() The various format options to draw a Graph can be accessed calling TMemStat memstat; memstat.Report("?") More info is available in the classes documentation. Note that this new package is currently available on Linux systems. It is not enabled by default. To enable it do ./configure --enable-memstat git-svn-id: http://root.cern.ch/svn/root/trunk@24338 27541ba8-7e3a-0410-8455-c3a389f83636 --- misc/memstat/Module.mk | 101 ++ misc/memstat/inc/LinkDef.h | 26 + misc/memstat/inc/LinkDefGUI.h | 14 + misc/memstat/inc/TMemStat.h | 125 +++ misc/memstat/inc/TMemStatDepend.h | 48 + misc/memstat/inc/TMemStatDrawDlg.h | 52 + misc/memstat/inc/TMemStatHelpers.h | 62 ++ misc/memstat/inc/TMemStatInfo.h | 227 +++++ misc/memstat/inc/TMemStatManager.h | 133 +++ misc/memstat/inc/TMemStatResource.h | 29 + misc/memstat/inc/TMemViewerGUI.h | 90 ++ misc/memstat/src/TMemStat.cxx | 1313 ++++++++++++++++++++++++++ misc/memstat/src/TMemStatDepend.cxx | 211 +++++ misc/memstat/src/TMemStatDrawDlg.cxx | 240 +++++ misc/memstat/src/TMemStatHelpers.cxx | 51 + misc/memstat/src/TMemStatInfo.cxx | 294 ++++++ misc/memstat/src/TMemStatManager.cxx | 645 +++++++++++++ misc/memstat/src/TMemViewerGUI.cxx | 418 ++++++++ 18 files changed, 4079 insertions(+) create mode 100644 misc/memstat/Module.mk create mode 100644 misc/memstat/inc/LinkDef.h create mode 100644 misc/memstat/inc/LinkDefGUI.h create mode 100644 misc/memstat/inc/TMemStat.h create mode 100644 misc/memstat/inc/TMemStatDepend.h create mode 100644 misc/memstat/inc/TMemStatDrawDlg.h create mode 100644 misc/memstat/inc/TMemStatHelpers.h create mode 100644 misc/memstat/inc/TMemStatInfo.h create mode 100644 misc/memstat/inc/TMemStatManager.h create mode 100644 misc/memstat/inc/TMemStatResource.h create mode 100644 misc/memstat/inc/TMemViewerGUI.h create mode 100644 misc/memstat/src/TMemStat.cxx create mode 100644 misc/memstat/src/TMemStatDepend.cxx create mode 100644 misc/memstat/src/TMemStatDrawDlg.cxx create mode 100644 misc/memstat/src/TMemStatHelpers.cxx create mode 100644 misc/memstat/src/TMemStatInfo.cxx create mode 100644 misc/memstat/src/TMemStatManager.cxx create mode 100644 misc/memstat/src/TMemViewerGUI.cxx diff --git a/misc/memstat/Module.mk b/misc/memstat/Module.mk new file mode 100644 index 00000000000..1e33538ddf6 --- /dev/null +++ b/misc/memstat/Module.mk @@ -0,0 +1,101 @@ +# Module.mk for newdelete module +# Copyright (c) 2005 Rene Brun and Fons Rademakers +# +# Author: Anar Manafov 17/06/2008 + +MODNAME := memstat +MODDIR := misc/$(MODNAME) +MODDIRS := $(MODDIR)/src +MODDIRI := $(MODDIR)/inc + +MEMSTATDIR := $(MODDIR) +MEMSTATDIRS := $(MEMSTATDIR)/src +MEMSTATDIRI := $(MEMSTATDIR)/inc + +##### libMemstat ##### +MEMSTATL := $(MODDIRI)/LinkDef.h +MEMSTATDS := $(MODDIRS)/G__memstat.cxx +MEMSTATDO := $(MEMSTATDS:.cxx=.o) +MEMSTATDH := $(MEMSTATDS:.cxx=.h) + +MEMSTATH := $(MODDIRI)/TMemStatHelpers.h $(MODDIRI)/TMemStatDepend.h $(MODDIRI)/TMemStat.h \ + $(MODDIRI)/TMemStatManager.h $(MODDIRI)/TMemStatInfo.h +MEMSTATS := $(MODDIRS)/TMemStat.cxx $(MODDIRS)/TMemStatManager.cxx \ + $(MODDIRS)/TMemStatDepend.cxx $(MODDIRS)/TMemStatInfo.cxx +MEMSTATO := $(MEMSTATS:.cxx=.o) + +MEMSTATDEP := $(MEMSTATO:.o=.d) $(MEMSTATDO:.o=.d) + +MEMSTATLIB := $(LPATH)/libMemStat.$(SOEXT) +MEMSTATMAP := $(MEMSTATLIB:.$(SOEXT)=.rootmap) + +##### libMemstatGUI ##### +MEMSTATGUIL := $(MODDIRI)/LinkDefGUI.h +MEMSTATGUIDS := $(MODDIRS)/G__memstatGUI.cxx +MEMSTATGUIDO := $(MEMSTATGUIDS:.cxx=.o) +MEMSTATGUIDH := $(MEMSTATGUIDS:.cxx=.h) + +MEMSTATGUIH := $(MODDIRI)/TMemStat.h $(MODDIRI)/TMemViewerGUI.h $(MODDIRI)/TMemStatDrawDlg.h $(MODDIRI)/TMemStatResource.h +MEMSTATGUIS := $(MODDIRS)/TMemViewerGUI.cxx $(MODDIRS)/TMemStatDrawDlg.cxx +MEMSTATGUIO := $(MEMSTATGUIS:.cxx=.o) + +MEMSTATGUIDEP := $(MEMSTATGUIO:.o=.d) $(MEMSTATGUIDO:.o=.d) + +MEMSTATGUILIB := $(LPATH)/libMemStatGUI.$(SOEXT) +MEMSTATGUIMAP := $(MEMSTATGUILIB:.$(SOEXT)=.rootmap) + +# used in the main Makefile +ALLHDRS += $(patsubst $(MODDIRI)/%.h,include/%.h,$(MEMSTATH)) +ALLHDRS += $(patsubst $(MODDIRI)/%.h,include/%.h,$(MEMSTATGUIH)) +ALLLIBS += $(MEMSTATLIB) $(MEMSTATGUILIB) +ALLMAPS += $(MEMSTATMAP) $(MEMSTATGUIMAP) + +# include all dependency files +INCLUDEFILES += $(MEMSTATDEP) + +##### local rules ##### +.PHONY: all-$(MODNAME) clean-$(MODNAME) distclean-$(MODNAME) + +include/%.h: $(MEMSTATDIRI)/%.h + cp $< $@ + +##### libMemstat ##### +$(MEMSTATLIB): $(MEMSTATO) $(MEMSTATDO) $(ORDER_) $(MAINLIBS) $(MEMSTATLIBDEP) + @$(MAKELIB) $(PLATFORM) $(LD) "$(LDFLAGS)" \ + "$(SOFLAGS)" libMemstat.$(SOEXT) $@ "$(MEMSTATO) $(MEMSTATDO)" + +$(MEMSTATDS): $(MEMSTATH) $(MEMSTATL) $(ROOTCINTTMPEXE) + @echo "Generating dictionary $@..." + $(ROOTCINTTMP) -f $@ -c $(MEMSTATH) $(MEMSTATL) + +$(MEMSTATMAP): $(RLIBMAP) $(MAKEFILEDEP) $(MEMSTATL) + $(RLIBMAP) -o $(MEMSTATMAP) -l $(MEMSTATLIB) \ + -d $(MEMSTATLIBDEPM) -c $(MEMSTATL) + +##### libMemstatGUI ##### +$(MEMSTATGUILIB): $(MEMSTATGUIO) $(MEMSTATGUIDO) $(ORDER_) $(MAINLIBS) $(MEMSTATGUILIBDEP) + @$(MAKELIB) $(PLATFORM) $(LD) "$(LDFLAGS)" \ + "$(SOFLAGS)" libMemstatGUI.$(SOEXT) $@ "$(MEMSTATGUIO) $(MEMSTATGUIDO)" + +$(MEMSTATGUIDS): $(MEMSTATGUIH) $(MEMSTATGUIL) $(ROOTCINTTMPEXE) + @echo "Generating dictionary $@..." + $(ROOTCINTTMP) -f $@ -c $(MEMSTATGUIH) $(MEMSTATGUIL) + +$(MEMSTATGUIMAP): $(RLIBMAP) $(MAKEFILEDEP) $(MEMSTATGUIL) + $(RLIBMAP) -o $(MEMSTATGUIMAP) -l $(MEMSTATGUILIB) \ + -d $(MEMSTATGUILIBDEPM) -c $(MEMSTATGUIL) + + +all-$(MODNAME): $(MEMSTATLIB) $(MEMSTATMAP) $(MEMSTATGUILIB) $(MEMSTATGUIMAP) + + +clean-$(MODNAME): + @rm -f $(MEMSTATO) $(MEMSTATDO) $(MEMSTATGUIO) $(MEMSTATGUIDO) + +clean:: clean-$(MODNAME) + +distclean-$(MODNAME): clean-$(MODNAME) + @rm -f $(MEMSTATDEP) $(MEMSTATDS) $(MEMSTATDH) $(MEMSTATLIB) $(MEMSTATMAP) + @rm -f $(MEMSTATGUIDEP) $(MEMSTATGUIDS) $(MEMSTATGUIDH) $(MEMSTATGUILIB) $(MEMSTATGUIMAP) + +distclean:: distclean-$(MODNAME) diff --git a/misc/memstat/inc/LinkDef.h b/misc/memstat/inc/LinkDef.h new file mode 100644 index 00000000000..12d944eafd2 --- /dev/null +++ b/misc/memstat/inc/LinkDef.h @@ -0,0 +1,26 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: M.Ivanov -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +#ifdef __CINT__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma extra_include "vector"; +#include <vector> + +#pragma link C++ typedef UIntVector_t; +#pragma link C++ typedef IntVector_t; + +#pragma link C++ class TInfoStamp+; +#pragma link C++ class TCodeInfo+; +#pragma link C++ class TStackInfo+; +#pragma link C++ class TMemStatManager+; +#pragma link C++ class TMemStat; +#pragma link C++ class TMemStatDepend; + +#pragma link C++ namespace Memstat; + +#pragma link C++ function Memstat::dig2bytes(Long64_t); + +#endif diff --git a/misc/memstat/inc/LinkDefGUI.h b/misc/memstat/inc/LinkDefGUI.h new file mode 100644 index 00000000000..0d37cde1989 --- /dev/null +++ b/misc/memstat/inc/LinkDefGUI.h @@ -0,0 +1,14 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: M.Ivanov -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +#ifdef __CINT__ +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#pragma link C++ typedef StringVector_t; + +#pragma link C++ class TMemViewerGUI+; +#pragma link C++ class TMemStatDrawDlg+; + +#endif diff --git a/misc/memstat/inc/TMemStat.h b/misc/memstat/inc/TMemStat.h new file mode 100644 index 00000000000..44ea6077fe3 --- /dev/null +++ b/misc/memstat/inc/TMemStat.h @@ -0,0 +1,125 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: D.Bertini and M.Ivanov 18/06/2007 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TMEMSTAT +#define ROOT_TMEMSTAT +// STD +#include <memory> +#include <vector> +#include <set> +// ROOT +#include "TString.h" +#include "TObjArray.h" +#include "TFile.h" +#include "TObjString.h" + +class TArrayI; +class TBits; +class TTree; +class TMemStatManager; +class TGraph; +class TCodeInfo; +class TStackInfo; +class TInfoStamp; + +typedef std::vector<UInt_t> UIntVector_t; +typedef std::vector<Int_t> IntVector_t; +typedef std::auto_ptr<TFile> TFilePtr; + +class TMemStat: public TObject +{ +public: + typedef std::set<std::string> Selection_t; + enum ESelection{ kFunction, kLibrary }; + + enum StatType { kTotalAllocCount = 0, kAllocCount = 2, kTotalAllocSize = 1, kAllocSize = 3, kUndef = 4}; + enum StampType { kCurrent = 0, kMaxSize = 1, kMaxCount = 2}; + enum OperType { kAND = 0, kOR = 1, kNOT = 2}; + +public: + TMemStat(Option_t* option = "read"); + virtual ~TMemStat(); + +public: + void SetAutoStamp(Int_t autoStampSize = 2000000, Int_t autoStampAlloc = 200000); + void SetCurrentStamp(const char *stampName); + void SetCurrentStamp(const TObjString &stampName); + TObjArray * GetStampList(); + void AddStamp(const char*stampName); + void Report(Option_t* option = ""); + void Paint(Option_t *option = ""); + void Draw(Option_t *option = ""); + void MakeReport(const char * lib = "", const char *fun = "", + Option_t* option = NULL, const char *fileName = ""); // make report for library + void MakeHisMemoryTime(); //draw histogram of memory usage + void MakeHisMemoryStamp(Int_t topDiff); //draw histogram of memory usage + Option_t *GetOption() const { + return fOption.Data(); + } + + void ResetSelection(); + void PrintCodeWithID(UInt_t index) const; + // if _deep is 0, then we use fStackDeep + void PrintStackWithID(UInt_t _id, UInt_t _deep = 0) const; + void SelectCode(const char * contlib = "", const char * contfunction = "", OperType oType = kOR); + void SelectStack(OperType oType = kOR); + void SortCode(StatType sortType, StampType stampType); + void SortStack(StatType sortType, StampType stampType); + void PrintCode(Int_t nentries = 10) const; + void PrintStack(Int_t nentries = 10, UInt_t deep = 1) const; + void GetFillSelection(Selection_t *_Container, ESelection _Selection) const; + +public: + StatType fSortStat; // sorting statistic type + StampType fSortStamp; // sorting stamp type + UInt_t fSortDeep; // deepnes of the information to be print - draw + UInt_t fStackDeep; // deepnes of the stack information + Int_t fSelected; // index of selected object + +private : + Bool_t GetMemStat(const char * fname, Int_t entry); + Bool_t EnabledCode(const TCodeInfo &info) const; + void MakeCodeArray(); + void MakeStackArray(); + void ProcessOption(Option_t *option); + TGraph* MakeGraph(StatType statType, Int_t id, Int_t type, Double_t &xmax, Double_t &ymax); + void MakeStampsText(); + void RefreshSelect(); + TObjArray *MakeGraphCode(StatType statType, Int_t nentries); + TObjArray *MakeGraphStack(StatType statType, Int_t nentries); + Int_t DistancetoPrimitive(Int_t px, Int_t py); + void ExecuteEvent(Int_t event, Int_t px, Int_t py); + +private: + Bool_t fIsActive; // is object attached to MemStat + UIntVector_t fSelectedCodeIndex; // vector of indexes of selected items - code + UIntVector_t fSelectedStackIndex; // vector of indexes of selected items - stack + TBits *fSelectedCodeBitmap; // bitmask of selected items - code + TBits *fSelectedStackBitmap; // bitmask of selected items - stack + TInfoStamp* fStackSummary; // summary information for selected stack + TFilePtr fFile; // current file with information - stamps + TTree *fTree; // current tree with inforamtion - stamps + TTree *fTreeSys; // tree with system information + TObjArray * fStampArray; // array of stamp names + TMemStatManager * fManager; // current MemStatManager + TObjArray *fArray; // array of objects to draw + TObjArray *fArrayGraphics; // array of graphic objects + IntVector_t fArrayIndexes; // indexes of selected objects + UInt_t fMaxStringLength; // max length of information string + Bool_t fOrder; // sorting order + TString fOption; // current options + TObjArray fDisablePrintLib; // disable printing for libraries + TObjArray fDisablePrintCode; // disable printing for libraries + + ClassDef(TMemStat, 0); +}; + +#endif diff --git a/misc/memstat/inc/TMemStatDepend.h b/misc/memstat/inc/TMemStatDepend.h new file mode 100644 index 00000000000..c87fff714ed --- /dev/null +++ b/misc/memstat/inc/TMemStatDepend.h @@ -0,0 +1,48 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: M.Ivanov 18/06/2007 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TMEMSTATDEPEND +#define ROOT_TMEMSTATDEPEND + +// +// TMemStatDepend +// Non standard C++ functions +// Needed for memory statistic + +#define _INIT_TOP_STECK extern void *g_global_stack_end; +#define _GET_TO_STECK g_global_stack_end = __builtin_frame_address(1); + +class TString; + +class TMemStatDepend +{ +public: + // + // Memory managment HOOK functions + // + typedef void* (*MallocHookFunc_t)(size_t size, const void *caller); + typedef void (*FreeHookFunc_t)(void* ptr, const void *caller); + + static MallocHookFunc_t GetMallocHook(); // malloc function getter + static FreeHookFunc_t GetFreeHook(); // free function getter + static void SetMallocHook(MallocHookFunc_t p); // malloc function setter + static void SetFreeHook(FreeHookFunc_t p); // free function setter + // + // Backtrace functions + // + static size_t Backtrace(void **trace, size_t size, Bool_t _bUseGNUBuildinBacktrace = kFALSE); + static char** BacktraceSymbols(void **trace, size_t size); + static void GetSymbols(void *pFunction, TString &strInfo, TString &strLib, TString &strFun, TString &strLine); + static void Demangle(char *codeInfo, TString &str); +}; + +#endif + diff --git a/misc/memstat/inc/TMemStatDrawDlg.h b/misc/memstat/inc/TMemStatDrawDlg.h new file mode 100644 index 00000000000..2ef84fece56 --- /dev/null +++ b/misc/memstat/inc/TMemStatDrawDlg.h @@ -0,0 +1,52 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: Anar Manafov (A.Manafov@gsi.de) 31/05/2008 +#ifndef _ROOT_TMEMSTATDRAWDLG_H +#define _ROOT_TMEMSTATDRAWDLG_H + +// STD +#include <vector> +#include <string> +// ROOT +#include "RQ_OBJECT.h" +#include "TGFrame.h" + +class TMemStat; +class TGComboBox; +class TGNumberEntry; +class TRootEmbeddedCanvas; + +typedef std::vector<std::string> StringVector_t; + +class TMemStatDrawDlg +{ + RQ_OBJECT("TMemStatDrawDlg") + + public: + TMemStatDrawDlg(const TGWindow *p, const TGWindow *main, TMemStat *MemStat); + virtual ~TMemStatDrawDlg(); + + // slots + void HandleDrawMemStat(); + void CloseWindow(); + + private: + void PlaceCtrls(TGCompositeFrame *frame); + void PlaceLBoxCtrl(TGCompositeFrame *frame, TGComboBox **box , + const std::string &Label, const StringVector_t &Vealues, Int_t resource); + void PlaceDeepCtrl(TGCompositeFrame *frame); + void PlaceEmbeddedCanvas(TGCompositeFrame *frame); + void ReDraw(); + + private: + TGTransientFrame *fMain; + TMemStat *fMemStat; + TGComboBox *fboxOrder; + TGComboBox *fboxSortStat; + TGComboBox *fboxSortStamp; + TGNumberEntry *fNmbStackDeep; + TGNumberEntry *fNmbSortDeep; + TGNumberEntry *fNmbMaxLength; + TRootEmbeddedCanvas *fEc; +}; + +#endif diff --git a/misc/memstat/inc/TMemStatHelpers.h b/misc/memstat/inc/TMemStatHelpers.h new file mode 100644 index 00000000000..a647b3a4470 --- /dev/null +++ b/misc/memstat/inc/TMemStatHelpers.h @@ -0,0 +1,62 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: Anar Manafov (A.Manafov@gsi.de) 09/05/2008 + +#ifndef ROOT_HELPERS_ +#define ROOT_HELPERS_ + +// ROOT +#include "TString.h" +#include "TObjString.h" +#include "TCollection.h" +// STD +#include <string> +#include <functional> +#include <algorithm> +#include <cctype> + + +class TObject; + +namespace Memstat +{ +std::string dig2bytes(Long64_t bytes); + +//______________________________________________________________________________ +struct SFind : std::binary_function<TObject*, TString, bool> { + bool operator()(TObject *_Obj, const TString &_ToFind) const + { + TObjString *str(dynamic_cast<TObjString*>(_Obj)); + if (!str) + return false; + return !str->String().CompareTo(_ToFind); + } +}; + +//______________________________________________________________________________ +template<class T> +Int_t find_string( const T &_Container, const TString &_ToFind ) +{ + // This function retuns an index in _Container of found element. + // Returns -1 if there was no element found. + + typedef TIterCategory<T> iterator_t; + + iterator_t iter(&_Container); + iterator_t found( + std::find_if(iter.Begin(), iterator_t::End(), bind2nd(SFind(), _ToFind)) + ); + return ( ( !(*found) )? -1: std::distance(iter.Begin(), found) ); +} + +//______________________________________________________________________________ +// HACK: because of the bug in gcc 3.3 we need to use this nasty ToLower and ToUpper instead of direct calls of tolower (tolower.. is inline in this version of std lib)... +struct ToLower +{ + char operator() ( char c ) const + { + return std::tolower( c ); + } +}; + +}; +#endif diff --git a/misc/memstat/inc/TMemStatInfo.h b/misc/memstat/inc/TMemStatInfo.h new file mode 100644 index 00000000000..41ab08da686 --- /dev/null +++ b/misc/memstat/inc/TMemStatInfo.h @@ -0,0 +1,227 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: D.Bertini and M.Ivanov 18/06/2007 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TMEMSTATINFO +#define ROOT_TMEMSTATINFO + + +//****************************************************************************// +// +// +// Memory statistic information +// TInfoStamp +// TCodeInfo +// TStackInfo +//****************************************************************************// + +// STD +#include <iosfwd> +#include <iomanip> +#include <sstream> +//ROOT +#include "TROOT.h" +#include "TObject.h" +// Memstat +#include "TMemStatHelpers.h" + +class TStackInfo; +class TMemStatManager; + + + +const int fields_length[] = {16, 7, 9, 15, 19, 12, 8}; + + +struct TInfoStamp: public TObject { + enum StampType { kCode, kStack }; + TInfoStamp(); //stamp of memory usage information + virtual ~TInfoStamp(); + void Print(Option_t* option = "") const; + Bool_t Equal(TInfoStamp&stamp); + void Inc(Int_t memSize); //increment counters -when memory allocated + void Dec(Int_t memSize); //decrement counters -when memory deallocated + friend std::ostream& operator<< (std::ostream &_ostream, const TInfoStamp &_this); + + Long64_t fTotalAllocCount; //total number of allocation for stack sequence + Long64_t fTotalAllocSize; //total size of allocated memory + Int_t fAllocCount; //current number of allocation-deallocation + Int_t fAllocSize; //current allocated size + Int_t fStampNumber; //stamp number + Int_t fID; //code ID number + Short_t fStampType; //stamp Type + + ClassDef(TInfoStamp, 1); +}; + + +struct TCodeInfo: public TObject { + TCodeInfo(); // store information about line of code + void SetInfo(void *info); + virtual ~TCodeInfo() { + } + void MakeStamp(Int_t stampNumber); + void Print(Option_t* option = "") const; + void Inc(Int_t memSize); //increment counters -when memory allocated + void Dec(Int_t memSize); //decrement counters -when memory deallocated + friend std::ostream& operator<< (std::ostream &_ostream, const TCodeInfo &_this); + + TInfoStamp fLastStamp; // last time stamp info + TInfoStamp fCurrentStamp; // current time stamp info + TInfoStamp fMaxStampSize; // max current size stamp + TInfoStamp fMaxStamp; // max current size stamp + Long64_t fCode; //pointer to the code + TString fInfo; //pointer desription + TString fFunction; //function + TString fLib; //library + UInt_t fCodeID; //ID number + + ClassDef(TCodeInfo, 1); +}; + + +struct TStackInfo: public TObject { + enum {kStackHistorySize = 50}; + UInt_t fSize; // size of the stack + TInfoStamp fLastStamp; // last time stamp info + TInfoStamp fCurrentStamp; // current time stamp info + TInfoStamp fMaxStampSize; // max current size stamp + TInfoStamp fMaxStamp; // max current size stamp + Int_t fNextHash; // index to the next info for given hash value + void **fStackSymbols; //!Stack Symbols + UInt_t *fSymbolIndexes; //[fSize]symbol indexes + UInt_t fStackID; //ID number + + TStackInfo(); + virtual ~TStackInfo() {} + void Init(Int_t stacksize, void **stackptrs, TMemStatManager *manager, Int_t ID); //initialization + void Inc(Int_t memSize, TMemStatManager *manager); //increment counters -when memory allocated + void Dec(Int_t memSize, TMemStatManager *manager); //decrement counters -when memory deallocated + ULong_t Hash() const; + Int_t Equal(UInt_t size, void **ptr); + void *StackAt(UInt_t i); + // TStackInfo *Next(); //index of the next entries + void MakeStamp(Int_t stampNumber); + static inline ULong_t HashStack(UInt_t size, void **ptr) { + return TString::Hash(ptr, size*sizeof(void*)); + } + friend std::ostream& operator << (std::ostream &_ostream, const TStackInfo &_this); + + ClassDef(TStackInfo, 1); +}; + + +struct TMemInfo { + void *fAddress; //mem address + size_t fSize; //size of the allocated memory + Int_t fStackIndex; //index of the stack info +}; + +struct TMemTable { + Int_t fAllocCount; //number of memory allocation blocks + Int_t fMemSize; //total memory allocated size + Int_t fTableSize; //amount of entries in the below array + Int_t fFirstFreeSpot; //where is the first free spot in the leaks array? + TMemInfo *fLeaks; //leak table +}; + +struct TDeleteTable { + Int_t fAllocCount; //how many memory blocks do we have + Int_t fTableSize; //amount of entries in the below array + TMemInfo *fLeaks; //leak table +}; + + + +inline void TInfoStamp::Inc(int memSize) +{ + fTotalAllocCount += 1; + fTotalAllocSize += memSize; + fAllocCount += 1; + fAllocSize += memSize; +} +inline void TInfoStamp::Dec(int memSize) +{ + fAllocCount -= 1; + fAllocSize -= memSize; +} +inline void TCodeInfo::Dec(int memSize) +{ + fCurrentStamp.Dec(memSize); +} + +inline ULong_t TStackInfo::Hash() const +{ + return HashStack(fSize, fStackSymbols); +} + +inline void *TStackInfo::StackAt(UInt_t i) +{ + return i < fSize ? fStackSymbols[i] : 0; +} + + +//______________________________________________________________________________ +template<class T> +std::ostream& StreemCurrAndMax(std::ostream &_ostream, const T &_this) +{ + std::ios::fmtflags old_flags(_ostream.flags(std::ios::left)); + + _ostream << "\n" + << std::setw(fields_length[0]) << "" + << std::setw(fields_length[1]) << "ID" + << std::setw(fields_length[2]) << "Sort" + << std::setw(fields_length[3]) << "TotalCount" + << std::setw(fields_length[4]) << "TotalSize" + << std::setw(fields_length[5]) << "Count" + << std::setw(fields_length[6]) << "Size" << std::endl; + + // Setting a bit nicer formating + // example: instead of 20600000 print 20,600,000 + std::locale loc(""); + std::locale loc_previous = _ostream.imbue(loc); + _ostream.precision(2); + _ostream << std::fixed; + + _ostream << std::setw(fields_length[0]) << "Current stamp"; + _ostream + << std::setw(fields_length[1]) << _this.fCurrentStamp.fStampNumber + << std::setw(fields_length[2]) << _this.fCurrentStamp.fID + << std::setw(fields_length[3]) << _this.fCurrentStamp.fTotalAllocCount + << std::setw(fields_length[4]) << Memstat::dig2bytes(_this.fCurrentStamp.fTotalAllocSize) + << std::setw(fields_length[5]) << _this.fCurrentStamp.fAllocCount + << std::setw(fields_length[6]) << Memstat::dig2bytes(_this.fCurrentStamp.fAllocSize) << std::endl; + + _ostream << std::setw(fields_length[0]) << "Max Alloc stamp"; + _ostream + << std::setw(fields_length[1]) << _this.fMaxStamp.fStampNumber + << std::setw(fields_length[2]) << _this.fMaxStamp.fID + << std::setw(fields_length[3]) << _this.fMaxStamp.fTotalAllocCount + << std::setw(fields_length[4]) << Memstat::dig2bytes(_this.fMaxStamp.fTotalAllocSize) + << std::setw(fields_length[5]) << _this.fMaxStamp.fAllocCount + << std::setw(fields_length[6]) << Memstat::dig2bytes(_this.fMaxStamp.fAllocSize) << std::endl; + + _ostream << std::setw(fields_length[0]) << "Max Size stamp"; + _ostream + << std::setw(fields_length[1]) << _this.fMaxStampSize.fStampNumber + << std::setw(fields_length[2]) << _this.fMaxStampSize.fID + << std::setw(fields_length[3]) << _this.fMaxStampSize.fTotalAllocCount + << std::setw(fields_length[4]) << Memstat::dig2bytes(_this.fMaxStampSize.fTotalAllocSize) + << std::setw(fields_length[5]) << _this.fMaxStampSize.fAllocCount + << std::setw(fields_length[6]) << Memstat::dig2bytes(_this.fMaxStampSize.fAllocSize); + + _ostream.imbue(loc_previous); + _ostream.flags(old_flags); + + return _ostream; +} + + +#endif diff --git a/misc/memstat/inc/TMemStatManager.h b/misc/memstat/inc/TMemStatManager.h new file mode 100644 index 00000000000..a77f3f69755 --- /dev/null +++ b/misc/memstat/inc/TMemStatManager.h @@ -0,0 +1,133 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: D.Bertini and M.Ivanov 18/06/2007 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TMEMSTATMANAGER +#define ROOT_TMEMSTATMANAGER + +//****************************************************************************// +// +// TMemStatManager +// Memory statistic manager class +// +//****************************************************************************// +// STD +#include <map> +#include <vector> +#include <memory> +#include <cstdlib> +// ROOT +#include "TObject.h" +#include "TTimeStamp.h" +// Memstat +#include "TMemStatDepend.h" +#include "TMemStatInfo.h" + + +class TTree; +class TStackInfo; + +typedef std::vector<Int_t> IntVector_t; +typedef std::auto_ptr<TFile> TFilePtr; + +class TMemStatManager: public TObject +{ +public: + typedef std::vector<TCodeInfo> CodeInfoContainer_t; + + enum StatusBits { + kUserDisable = BIT(18), // user disable-enable switch switch + kStatDisable = BIT(16), // true if disable statistic + kStatRoutine = BIT(17) // indicator inside of stat routine (AddPointer or FreePointer) + }; + enum EDumpTo { Tree, SysTree }; + + TMemStatManager(); + virtual ~TMemStatManager(); + + void Enable(); //enable memory statistic + void Disable(); //dissable memory statisic + void SetAutoStamp(UInt_t sizeMem, UInt_t n, UInt_t max) { + fAutoStampSize = sizeMem; + fAutoStampN = n; + fAutoStampDumpSize = max; + } + void AddStamps(const char * stampname = 0); //add stamps to the list of stamps for changed stacks + static void SAddStamps(const Char_t * stampname); // static version add stamps to the list of stamps for changed stacks + + static TMemStatManager* GetInstance(); //get instance of class - ONLY ONE INSTANCE + static void Close(); //close MemStatManager + TInfoStamp &AddStamp(); //add one stamp to the list of stamps + TCodeInfo &GetCodeInfo(void *address); + UInt_t GetCodeInfoIndex(void *address) { + return fCodeInfoMap[address]; + } + void DumpTo(EDumpTo _DumpTo, Bool_t _clearStamps = kTRUE, const char * _stampName = 0); //write current status to file + +public: + typedef void (*StampCallback_t)(const Char_t * desription); + //stack data members + IntVector_t fSTHashTable; //!pointer to the hash table + Int_t fCount; //!number of entries in table + Int_t fStampNumber; //current stamp number + std::vector<TStackInfo> fStackVector; // vector withstack symbols + std::vector<TInfoStamp> fStampVector; // vector of stamp information + std::vector<TTimeStamp> fStampTime; // vector of stamp information + CodeInfoContainer_t fCodeInfoArray; // vector with code info + std::map<const void*, UInt_t> fCodeInfoMap; //! map of code information + Int_t fDebugLevel; //!debug level + TMemStatManager::StampCallback_t fStampCallBack; //!call back function + void SetUseGNUBuildinBacktrace(Bool_t _NewVal) { + fUseGNUBuildinBacktrace = _NewVal; + } + +protected: + TMemStatDepend::MallocHookFunc_t fPreviousMallocHook; //!old malloc function + TMemStatDepend::FreeHookFunc_t fPreviousFreeHook; //!old free function + void Init(); + TStackInfo *STAddInfo(Int_t size, void **stackptrs); + TStackInfo *STFindInfo(Int_t size, void **stackptrs); + void RehashLeak(Int_t newSize); //rehash leak pointers + void *AddPointer(size_t size, void *ptr = 0); //add pointer to the table + void FreePointer(void *p); //free pointer + static void *AllocHook(size_t size, const void* /*caller*/); + static void FreeHook(void* ptr, const void* /*caller*/); + TInfoStamp fLastStamp; //last written stamp + TInfoStamp fCurrentStamp; //current stamp + UInt_t fAutoStampSize; //change of size invoking STAMP + UInt_t fAutoStampN; //change of number of allocation STAMP + UInt_t fAutoStampDumpSize; // + Int_t fMinStampSize; // the minimal size to be dumped to tree + // memory infomation + Int_t fSize; //!size of hash table + TMemTable **fLeak; //!pointer to the hash table + Int_t fAllocCount; //!number of memory allocation blocks + TDeleteTable fMultDeleteTable; //!pointer to the table + TFilePtr fDumpFile; //!file to dump current information + TTree *fDumpTree; //!tree to dump information + TTree *fDumpSysTree; //!tree to dump information + static TMemStatManager *fgInstance; // pointer to instance + static void *fgStackTop; // stack top pointer + + void free_hashtable() { + if (!fLeak) + return; + + for (Int_t i = 0; i < fSize; ++i) + free(fLeak[i]); + free(fLeak); + } + + Bool_t fUseGNUBuildinBacktrace; + + ClassDef(TMemStatManager, 1); +}; + +#endif diff --git a/misc/memstat/inc/TMemStatResource.h b/misc/memstat/inc/TMemStatResource.h new file mode 100644 index 00000000000..76af57b74a9 --- /dev/null +++ b/misc/memstat/inc/TMemStatResource.h @@ -0,0 +1,29 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: Anar Manafov (A.Manafov@gsi.de) 30/05/2008 + +#ifndef ROOT_MEMSTAT_RESOURCE_ +#define ROOT_MEMSTAT_RESOURCE_ + +// radio buttons of SortStat IDs +#define rbtnTotalAllocCount 30 +#define rbtnTotalAllocSize 31 +#define rbtnAllocCount 32 +#define rbtnAllocSize 33 + +// radio buttons of SortStamp IDs +#define rbtnCurrent 40 +#define rbtnMaxSize 41 +#define rbtnMaxCount 42 + +// STAMPs list box +#define lstStamps 50 + +// Draw TMemStatDlg +#define resCBoxOrder 100 +#define resCBoxSortStat 101 +#define resCBoxSortStamp 102 +#define resNmbStackDeep 103 +#define resNmbSortDeep 104 +#define resNmbMaxLength 105 + +#endif diff --git a/misc/memstat/inc/TMemViewerGUI.h b/misc/memstat/inc/TMemViewerGUI.h new file mode 100644 index 00000000000..9a972a1170b --- /dev/null +++ b/misc/memstat/inc/TMemViewerGUI.h @@ -0,0 +1,90 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: M.Ivanov -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ +#ifndef ALITPCCALIBVIEWERGUI +#define ALITPCCALIBVIEWERGUI + +/* Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * + * See cxx source for full Copyright notice */ + +/* $Id: TMemViewerGUI.h,v */ + +/////////////////////////////////////////////////////////////////////////////// +// // +// GUI for the AliTPCCalibViewer // +// used for the calibration monitor // +// // +/////////////////////////////////////////////////////////////////////////////// + +// STD +#include <string> +#include <memory> +// ROOT +#include "TGFrame.h" + +class TGTextView; +class TGNumberEntry; +class TGComboBox; + +class TMemViewerGUI : public TGCompositeFrame +{ +protected: + TMemStat *fViewer; // CalibViewer object used for drawing + TGTextView *fText; // text widget + TGNumberEntry *fNmbStackDeep; // number entry box for specifying the stack deepness + TGNumberEntry *fNmbSortDeep; // number entry box for specifying the number of stamps + std::string fCurLib; + std::string fCurFunc; + + +protected: + void MakeContSortStat(TGCompositeFrame *frame); + void MakeContSortStamp(TGCompositeFrame *frame); + void MakeContDeep(TGCompositeFrame *frame); + void MakeContSelect(TGCompositeFrame *frame); + void MakeStampList(TGCompositeFrame *frame); + void MakeDrawButton(TGCompositeFrame *frame); + void MakeSelection(TGCompositeFrame *frame); + + const Option_t *GetOption() const; // get option + void Initialize(Option_t* option); // initializes the GUI with default settings and opens tree for drawing + void MakePrint(); // get print + + template< class T > + void HandleRButtons(Int_t id, Int_t FirstBtnId, T *ViewerSortType); + +public: + TMemViewerGUI(const TGWindow *p, UInt_t w, UInt_t h, Option_t* option = "read"); + virtual ~TMemViewerGUI(); + + static void ShowGUI(); // initialize and show GUI for presentation + + void HandleButtonsSortStat(Int_t id = -1); // handles mutual radio buuton for sort stat + void HandleButtonsSortStamp(Int_t id = -1); // handles mutual radio buuton for sort stamp + void HandleDeep(Long_t id); // handles stack deep and nrows + void HandleStampSelect(const char*); + void HandleDrawMemStat(); + void HandleFuncSelect(const char*); + void HandleLibSelect(const char*); + + ClassDef(TMemViewerGUI, 0) +}; + +//______________________________________________________________________________ +template< class T > +void TMemViewerGUI::HandleRButtons(Int_t id, Int_t FirstBtnId, T *ViewerSortType) +{ + // handles mutual radio button exclusions + *ViewerSortType = static_cast<T>(id - FirstBtnId); + MakePrint(); +} + + +#endif diff --git a/misc/memstat/src/TMemStat.cxx b/misc/memstat/src/TMemStat.cxx new file mode 100644 index 00000000000..0c9bec1ddc0 --- /dev/null +++ b/misc/memstat/src/TMemStat.cxx @@ -0,0 +1,1313 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: M.Ivanov 18/06/2007 -- Anar Manafov (A.Manafov@gsi.de) 29/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ +//______________________________________________________________________________ +/* Begin_Html +<center><h2>Mem stat class</h2></center> +TMemStat - class for visualization of the memory usage +<p> +Principle: +Hook functions for alloc and free are used. +All calls to alloc (new) and free (delete) are catched and the statistical information is collected. +The information is collected per stack trace (Unique identifier and per functions). Following informations are collected as function of time: +<ul> +<li>Total number of allocations </li> +<li>Total allocation size </li> +<li>Allocation count </li> +<li>Allocation size </li> +</ul> + +How to use it: + <n> Create memstat object + TMemStat memstat(autoStamSize=10000, autoStampCount=1000); + <ul> + <li> autoStamSize - The increase - decrease of size of memory after which stamps are generated </li> + <li> autoStampCount - The increase - decrease of memory allocation counter after which stamps are generated</li> + </ul> +User request for adding the named memory stamp is supported. +<p> memstat.AddStamp("mystamp") +<p> + +The file "memstat.root" is created after destruction of object. +This class supports following functions for standard user: +<ul> +<li> constructor - TMemStat memstat.(filename) </li> +<li> Report </li> +<li> Draw </li> +<li> SelectCode(libname, functionname) </li> +<li> SelectStack() </li> +</ul> +The various format options to draw a Graph can be accessed calling +<p> + TMemStat memstat; +<p> + memstat.Report("?") + + +<p> +Supported options: +<ul> +<li> order : 0 - increasing 1 - decreasing</li> +<li> sortstat : 0 - TotalAllocCount 1 - TotalAlocSize 2 - AllocCount 3 - AllocSize</li> +<li> sortstamp : 0 - Current 1 - MaxSize 2 - MaxCount</li> +<li> sortdeep : (0-inf) number of info to print</li> +<li> stackdeep : (0-inf) deepnes of stack</li> +<li> Example : order 0 sortstat 3 sortstamp 0 sortdeep 10 stackdeep 5 maxlength 50 </li> + +</ul> +<p> + +The picture below gives an example: +End_Html +Begin_Macro(source) +{ + TCanvas *c1 = new TCanvas("c1","A Simple MemStat Example",200,10,700,1000); + + TMemStat *memstat = new TMemStat(30000,10000); + for (Int_t i=0;i<11000;i++) { + TObjString * object = new TObjString(Form("Object%d",i)); + if (i%2) delete object; + } + for (Int_t i=0;i<12000;i++) { + TString * object2 = new TString(i); + if (i%2) delete object2; + } + for (Int_t i=0;i<1300;i++) { + TClonesArray *array = new TClonesArray("TVectorD"); + //array.ExpandCreatFast(i); + } + delete memstat; + memstat = new TMemStat("memstat.root"); + c1->Divide(1,2); + c1->cd(1); + memstat->Report("order 0 sortstat 2 sortstamp 1 sortdeep 10 stackdeep 5 maxlength 50"); + memstat->Draw("order 0 sortstat 2 sortstamp 1 sortdeep 10 stackdeep 5 maxlength 50"); + c1->cd(2); + memstat->Report("order 0 sortstat 3 sortstamp 2 sortdeep 10 stackdeep 5 maxlength 50"); + memstat->Draw("order 0 sortstat 3 sortstamp 2 sortdeep 10 stackdeep 5 maxlength 50"); + + return c1; +} +End_Macro */ + +// STD +#include <map> +#include <vector> +#include <iostream> +// ROOT +#include "TTree.h" +#include "TMath.h" +#include "TArrayI.h" +#include "TBits.h" +#include "TCanvas.h" +#include "TPad.h" +#include "TAxis.h" +#include "TGraph.h" +#include "TLegend.h" +#include "TText.h" +#include "TLine.h" +#include "THStack.h" +#include "TSystem.h" +// Memstat +#include "TMemStat.h" +#include "TMemStatInfo.h" +#include "TMemStatManager.h" +#include "TMemStatHelpers.h" + + +ClassImp(TMemStat) + +using namespace std; +using namespace Memstat; + +typedef vector<Long64_t> Long64Vector_t; +typedef vector<Double_t> DoubleVector_t; + +_INIT_TOP_STECK; + +struct SFillSelection: public binary_function< + TMemStatManager::CodeInfoContainer_t::value_type, + TMemStat::ESelection, + TMemStat::Selection_t::value_type> +{ + TMemStat::Selection_t::value_type operator() ( + const TMemStatManager::CodeInfoContainer_t::value_type &_code_info, + TMemStat::ESelection _Selection ) const + { + switch ( _Selection ) + { + case TMemStat::kFunction: + return _code_info.fFunction.Data(); + case TMemStat::kLibrary: + // we need only names of libraies + return gSystem->BaseName(_code_info.fLib.Data()); + default: + return string(); + } + } +}; + +//______________________________________________________________________________ +TMemStat::TMemStat(Option_t* option): + TObject(), + fSortStat(kAllocSize), + fSortStamp(kCurrent), + fSortDeep(10), + fStackDeep(20), + fSelected(0), + fIsActive(kFALSE), + fSelectedCodeBitmap(NULL), + fSelectedStackBitmap(NULL), + fStackSummary(NULL), + fTree(NULL), + fTreeSys(NULL), + fStampArray(NULL), + fManager(NULL), + fArray(NULL), + fArrayGraphics(NULL), + fMaxStringLength(50), + fOrder(kFALSE) +{ + // Supported options: + // "new" - start to collect memory allocations stamps + // "read" - analyze previously collected data + // "gnubuildin" - if declared, then TMemStat will use gcc build-in function, + // otherwise glibc backtrace will be used + // + // Default: "read" + // Note: Currently TMemStat uses a hard-coded output file name (for writing/reading) = "memstat.root"; + + // It marks the highest used stack address. + _GET_TO_STECK; + + string opt(option); + transform( opt.begin(), opt.end(), opt.begin(), + Memstat::ToLower() ); + + if ( opt.find("new") != string::npos) // Processing "NEW" + { + SetAutoStamp(); + const Bool_t useBuildin = (opt.find("gnubuildin") != string::npos)? kTRUE: kFALSE; + TMemStatManager::GetInstance()->SetUseGNUBuildinBacktrace(useBuildin); + TMemStatManager::GetInstance()->Enable(); + // set this variable only if "NEW" mode is active + fIsActive = kTRUE; + } + else if ( opt.find("read") != string::npos) // Processing "READ" + { + // GetData from existing file + GetMemStat("memstat.root", -1); + + // default disabling + fDisablePrintLib.SetOwner(); + fDisablePrintLib.AddLast(new TObjString("libRIO")); + fDisablePrintCode.SetOwner(); + fDisablePrintCode.AddLast(new TObjString("TClass::Streamer")); + // set default option + ProcessOption("order 0 sortstat 3 sortstamp 0 sortdeep 30 stackdeep 15 maxlength 50"); + } + else + { + Error("TMemStat", "Invalid option"); + } + +} + +//______________________________________________________________________________ +TMemStat::~TMemStat() +{ + // destructor + + if (fIsActive) { + TMemStatManager::GetInstance()->Disable(); + TMemStatManager::GetInstance()->Close(); + } + + delete fStackSummary; + delete fSelectedCodeBitmap; + delete fSelectedStackBitmap; +} + +//______________________________________________________________________________ +void TMemStat::SetAutoStamp(Int_t autoStampSize, Int_t autoStampAlloc) +{ + // Change default values of the auto stamping + // autoStampSize [in] - size of invoking STAMPs + // autoStampAlloc [in] - a number of allocations + + if (autoStampSize > 0) + TMemStatManager::GetInstance()->SetAutoStamp(autoStampSize, autoStampAlloc, 10000); +} + +//______________________________________________________________________________ +void TMemStat::SetCurrentStamp(const char *stampName) +{ + // Getvalues for iven stamp + + GetStampList(); + + const Int_t entry = find_string(*fStampArray, stampName); + GetMemStat(0, entry); +} + +//______________________________________________________________________________ +void TMemStat::SetCurrentStamp(const TObjString &stampName) +{ + SetCurrentStamp(stampName.GetString()); +} + +//______________________________________________________________________________ +TObjArray* TMemStat::GetStampList() +{ + if (fStampArray) + return fStampArray; + + if (!fTreeSys) + return NULL; + + TObjString str; + TObjString *pstr = &str; + fStampArray = new TObjArray; + fTreeSys->SetBranchAddress("StampName.", &pstr); + for (Int_t i = 0; i < fTreeSys->GetEntries(); ++i) { + fTreeSys->GetEntry(i); + fStampArray->AddLast(str.Clone()); + } + return fStampArray; +} + +//______________________________________________________________________________ +Int_t TMemStat::DistancetoPrimitive(Int_t px, Int_t py) +{ + // Return distance of the mouse to the TMemStat object + + const Int_t kMinDist = 10; + if (!fArray) + return -1; + + const Int_t big = 9999; + const Int_t kBoundary = 6; + Int_t puxmin = gPad->XtoAbsPixel(gPad->GetUxmin()); + Int_t puymin = gPad->YtoAbsPixel(gPad->GetUymin()); + Int_t puxmax = gPad->XtoAbsPixel(gPad->GetUxmax()); + Int_t puymax = gPad->YtoAbsPixel(gPad->GetUymax()); + + // return if point is not in the graph area + if (px <= puxmin + kBoundary) + return big; + if (py >= puymin - kBoundary) + return big; + if (px >= puxmax - kBoundary) + return big; + if (py <= puymax + kBoundary) + return big; + + fSelected = -1; + Int_t mindist = 9999; + for (Int_t i = 0; i < fArray->GetSize(); ++i) { + if (!fArray->At(i)) + continue; + const Int_t dist = fArray->At(i)->DistancetoPrimitive(px, py); + if (dist < mindist) { + mindist = dist; + fSelected = i; + } + } + if (mindist > kMinDist) + fSelected = -1; + return -1; +} + +//______________________________________________________________________________ +void TMemStat::ExecuteEvent(Int_t event, Int_t /* px*/, Int_t /*py*/) +{ + // function called when clicking with the mouse on a TMemStat object + + switch (event) { + case kButton1Down: + if (fArray && fSelected >= 0) { + const Int_t uid = fArrayIndexes[fSelected]; + cout << endl; + (uid >= 0) ? PrintStackWithID(uid) : PrintCodeWithID(-uid); + } + break; + case kMouseMotion: + break; + case kButton1Motion: + break; + case kButton1Up: + break; + } +} + +//______________________________________________________________________________ +void TMemStat::AddStamp(const char*stampName) +{ + // Add named stamp to the file + + TMemStatManager::GetInstance()->AddStamps(stampName); +} + +//______________________________________________________________________________ +void TMemStat::RefreshSelect() +{ + if (fSelectedCodeIndex.empty()) + SelectCode(NULL, NULL, TMemStat::kOR); + + if (fSelectedStackIndex.empty()) + SelectStack(TMemStat::kOR); +} + +//______________________________________________________________________________ +void TMemStat::Report(Option_t* option) +{ + // Report function + // Supported options: + // + // order : 0 - increasing 1 - decreasing + // sortstat : 0 - TotalAllocCount 1 - TotalAlocSize 2 - AllocCount 3 - AllocSize + // sortstamp : 0 - Current 1 - MaxSize 2 - MaxCount + // sortdeep : (0-inf) number of info to print + // stackdeep : (0-inf) deepnes of stack + // Example : order 0 sortstat 3 sortstamp 0 sortdeep 10 stackdeep 5 maxlength 50 + + ProcessOption(option); + + TString opt(option); + opt.ToLower(); + if (opt.Contains("?")) + return; + + RefreshSelect(); + + if (!(opt.Contains("code"))) { + SortStack(fSortStat, fSortStamp); + PrintStack(fSortDeep, fStackDeep); + } else { + SortCode(fSortStat, fSortStamp); + PrintCode(fSortDeep); + } +} + +//______________________________________________________________________________ +void TMemStat::Draw(Option_t *option) +{ + // Draw the memory statistic + // call ::Report("?") to see possible options and meaning + + if (!gPad) { + new TCanvas; + gPad->SetTopMargin(0.2); + gPad->SetRightMargin(0.3); + gPad->SetLeftMargin(0.10); + } else { + gPad->Clear(); + } + + ProcessOption(option); + TString opt(option); + opt.ToLower(); + if (opt.Contains("?")) + return; + + RefreshSelect(); + + if (!opt.Contains("code")) { + SortStack(fSortStat, fSortStamp); + fArray = MakeGraphStack(fSortStat, fSortDeep); + } else { + SortCode(fSortStat, fSortStamp); + fArray = MakeGraphCode(fSortStat, fSortDeep); + } + + MakeStampsText(); + if (gPad) { + fArray->At(0)->Draw("alp"); + gPad->Update(); + + TLegend * legend = new TLegend(0.75, 0.1, 0.99, 0.9, "Memory statistic"); + for (Int_t i = 0;i < fArray->GetEntries();i++) { + fArray->At(i)->Draw("lp"); + cout << i << '\t' << fArray->At(i)->GetName() << endl; + legend->AddEntry(fArray->At(i), fArray->At(i)->GetName()); + gPad->Update(); + } + legend->Draw(); + fArray->AddLast(legend); + for (Int_t i = 0; i < fArrayGraphics->GetEntries(); i++) { + TText *ptext = dynamic_cast<TText*>(fArrayGraphics->At(i)); + if (ptext) { + ptext->SetY(gPad->GetUymax()); + ptext->SetTextAngle(45); + ptext->SetTextSizePixels(12); + ptext->SetTextAlign(13); + ptext->Draw(""); + } + TLine *pline = dynamic_cast<TLine*>(fArrayGraphics->At(i)); + if (pline) { + pline->SetY2(gPad->GetUymax()); + pline->SetLineStyle(2); + pline->Draw(""); + } + } + } + AppendPad(); +} + +//______________________________________________________________________________ +void TMemStat::Paint(Option_t * /* option */) +{ + // Paint function +} + +//______________________________________________________________________________ +void TMemStat::ResetSelection() +{ + // reset all selections + + fSelectedCodeIndex.clear(); + fSelectedStackIndex.clear(); + + delete fSelectedCodeBitmap; + fSelectedCodeBitmap = NULL; + delete fSelectedStackBitmap; + fSelectedStackBitmap = NULL; + delete fStackSummary; + fStackSummary = NULL; +} + +//______________________________________________________________________________ +Bool_t TMemStat::GetMemStat(const char * fname, Int_t entry) +{ + // Get memstat from tree + + if (fname != 0) { + fFile.reset(TFile::Open(fname)); + if (!fFile.get() || fFile->IsZombie()) + return kFALSE; + + fTree = dynamic_cast<TTree*>(fFile->Get("MemStat")); + if (!fTree) + return kFALSE; + + fTreeSys = dynamic_cast<TTree*>(fFile->Get("MemSys")); + if (!fTreeSys) + return kFALSE; + } + + TMemStatManager *man(NULL); + // TODO: needs to be investigated. + // There was a crash, happens when user reselect stamps list after TMemStat Draw has been called. + // The crash (SEGFAULT) happens in fTree->GetEntry(entry) in access of its buffer. + // ResetBranchAddresses helped, but it is not clear whether this fix correct or not. + fTree->ResetBranchAddresses(); + fTree->SetBranchAddress("Manager", &man); + + if ( (entry < 0) || (entry >= fTree->GetEntries()) ) + entry = fTree->GetEntries() - 1; + + fTree->GetEntry(entry); + fManager = man; + return kTRUE; +} + +//______________________________________________________________________________ +void TMemStat::PrintCodeWithID(UInt_t id) const +{ + // print information for code with ID + + if (!fManager) + return; + if (id > fManager->fCodeInfoArray.size()) + return; + fManager->fCodeInfoArray[id].Print(); +} + +//______________________________________________________________________________ +void TMemStat::SelectCode(const char *contlib, const char *contfunction, OperType oType) +{ + // select code with given mask + // contlib - select only code containing contlib in library path + // contfunction - select only code with function name containing contfunction + // oType - logiacal operation - AND and Or is suported + // By default all code is enabled + + if (!fManager) { + Error("SelectCode", "MemStat Manager is the NULL object."); + return; + } + + const size_t entries = fManager->fCodeInfoArray.size(); + + fSelectedCodeIndex.clear(); + + if (!fSelectedCodeBitmap) { + fSelectedCodeBitmap = new TBits(entries); + for (UInt_t i = 0; i < entries; ++i) + fSelectedCodeBitmap->SetBitNumber(i, kFALSE); + } + + switch (oType) { + case kOR: + for (UInt_t i = 0; i < entries; ++i) { + if (fSelectedCodeBitmap->TestBitNumber(i)) + continue; + const TCodeInfo &info = fManager->fCodeInfoArray[i]; + if (contlib && (!(info.fLib.Contains(contlib)))) + continue; + if (contfunction && (!(info.fFunction.Contains(contfunction)))) + continue; + if (info.fFunction.Contains("TObject::operator new")) + continue; + fSelectedCodeBitmap->SetBitNumber(i); + } + break; + case kAND: + for (UInt_t i = 0; i < entries; i++) { + if (!(fSelectedCodeBitmap->TestBitNumber(i))) + continue; + const TCodeInfo&info = fManager->fCodeInfoArray[i]; + fSelectedCodeBitmap->SetBitNumber(i, kFALSE); + if (contlib && (!(info.fLib.Contains(contlib)))) + continue; + if (contfunction && (!(info.fFunction.Contains(contfunction)))) + continue; + if (info.fFunction.Contains("TObject::operator new")) + continue; + fSelectedCodeBitmap->SetBitNumber(i, kTRUE); + } + break; + case kNOT: + break; + } + + MakeCodeArray(); +} + +//______________________________________________________________________________ +void TMemStat::SelectStack(OperType oType) +{ + // select stack containig the selected code + // oType - And and OR is supported (AND, OR in respect with previous selection) + + if (!fSelectedCodeBitmap || !fManager) + return; + + const size_t entries = fManager->fStackVector.size(); + + fSelectedStackIndex.clear(); + + if (!fSelectedStackBitmap) { + fSelectedStackBitmap = new TBits(entries); + for (UInt_t i = 0; i < entries; ++i) + fSelectedStackBitmap->SetBitNumber(i, kFALSE); + } + + switch (oType) { + case kOR: + for (UInt_t i = 0; i < entries; ++i) { + if (fSelectedStackBitmap->TestBitNumber(i)) + continue; + const TStackInfo &info = fManager->fStackVector[i]; + for (UInt_t icode = 0; icode < info.fSize; ++icode) { + if (fSelectedCodeBitmap->TestBitNumber(info.fSymbolIndexes[icode])) { + fSelectedStackBitmap->SetBitNumber(i, kTRUE); + } + } + } + break; + case kAND: + for (UInt_t i = 0; i < entries; ++i) { + if (!(fSelectedStackBitmap->TestBitNumber(i))) + continue; + const TStackInfo &info = fManager->fStackVector[i]; + fSelectedStackBitmap->SetBitNumber(i, kFALSE); + for (UInt_t icode = 0; icode < info.fSize; ++icode) { + if (fSelectedCodeBitmap->TestBitNumber(info.fSymbolIndexes[icode])) { + fSelectedStackBitmap->SetBitNumber(i, kTRUE); + } + } + } + break; + case kNOT: + break; + } + + MakeStackArray(); +} + +//______________________________________________________________________________ +void TMemStat::SortCode(StatType sortType, StampType stampType) +{ + // sort code according statistical criteria + // sortType + // stampType + + if (fSelectedCodeIndex.empty() || !fManager) + return; + + const Int_t size = fSelectedCodeIndex.size(); + Long64Vector_t values(size); + TArrayI indexes(size); + + const size_t entries = fManager->fCodeInfoArray.size(); + Int_t iselected = 0; + for (UInt_t icode = 0; icode < entries; ++icode) { + if (!(fSelectedCodeBitmap->TestBitNumber(icode))) + continue; + TInfoStamp * info = 0; + switch (stampType) { + case kCurrent: + info = &(fManager->fCodeInfoArray[icode].fCurrentStamp); + break; + case kMaxSize: + info = &(fManager->fCodeInfoArray[icode].fMaxStampSize); + break; + case kMaxCount: + info = &(fManager->fCodeInfoArray[icode].fMaxStamp); + break; + } + + if (!info) + break; + + indexes[iselected] = icode; + + switch (sortType) { + case kTotalAllocCount: + values[iselected] = info->fTotalAllocCount; + break; + case kAllocCount: + values[iselected] = info->fAllocCount; + break; + case kTotalAllocSize: + values[iselected] = info->fTotalAllocSize; + break; + case kAllocSize: + values[iselected] = info->fAllocSize; + break; + case kUndef: + break; + } + + ++iselected; + } + + TArrayI sortIndexes(size); + TMath::Sort(iselected, &values[0], &sortIndexes[0], fOrder); + + fSelectedCodeIndex.clear(); + fSelectedCodeIndex.reserve(iselected); + for (Int_t i = 0; i < iselected; ++i) + fSelectedCodeIndex.push_back(indexes[sortIndexes[i]]); +} + +//______________________________________________________________________________ +void TMemStat::SortStack(StatType sortType, StampType stampType) +{ + // sort code according statistical criteria + // sortType + // stampType + + if (!fSelectedCodeBitmap || !fManager) + return; + + const size_t entries = fManager->fStackVector.size(); + Long64Vector_t values(entries); + TArrayI indexes(entries); + + UInt_t iselected = 0; + for (UInt_t istack = 0; istack < entries; ++istack) { + if (!(fSelectedStackBitmap->TestBitNumber(istack))) + continue; + TInfoStamp * info(NULL); + switch (stampType) { + case kCurrent: + info = &(fManager->fStackVector[istack].fCurrentStamp); + break; + case kMaxSize: + info = &(fManager->fStackVector[istack].fMaxStampSize); + break; + case kMaxCount: + info = &(fManager->fStackVector[istack].fMaxStamp); + break; + } + + indexes[iselected] = istack; + + switch (sortType) { + case kTotalAllocCount: + values[iselected] = info->fTotalAllocCount; + break; + case kAllocCount: + values[iselected] = info->fAllocCount; + break; + case kTotalAllocSize: + values[iselected] = info->fTotalAllocSize; + break; + case kAllocSize: + values[iselected] = info->fAllocSize; + break; + case kUndef: + break; + } + if (values[iselected] == 0) continue; + ++iselected; + } + TArrayI sortIndexes(entries); + TMath::Sort(iselected, &values[0], &sortIndexes[0], fOrder); + const Int_t sizeOut = TMath::Min(fSortDeep, iselected); + fSelectedStackIndex.clear(); + fSelectedStackIndex.reserve(sizeOut); + if (fOrder) { + for (Int_t i = 0; i < sizeOut; ++i) + fSelectedStackIndex.push_back(indexes[sortIndexes[i]]); + } else { + const Int_t first = (iselected < fSortDeep) ? 0 : iselected - fSortDeep; + for (UInt_t i = first; i < (first + fSortDeep) && i < iselected; ++i) { + const UInt_t indexS = sortIndexes[i]; + if (indexS >= entries) { + cerr << "Error 0 \n"; + continue; + } + if (static_cast<size_t>(indexes[indexS]) >= entries) { + cerr << "Error 1 \n"; + continue; + } + const Long64_t value = values[indexS]; + if (0 == value) { + cerr << "Error 2\n"; + continue; + } + fSelectedStackIndex.push_back(indexes[indexS]); + } + } +} + +//______________________________________________________________________________ +void TMemStat::MakeCodeArray() +{ + // PRIVATE: make code index accoring tbit mask + + if (!fManager) + return; + + Int_t nselected = 0; + size_t csize = fManager->fCodeInfoArray.size(); + + for (UInt_t i = 0; i < csize; ++i) + if (fSelectedCodeBitmap->TestBitNumber(i)) + ++nselected; + + fSelectedCodeIndex.clear(); + fSelectedCodeIndex.reserve(nselected); + for (UInt_t i = 0; i < csize; ++i) { + if (fSelectedCodeBitmap->TestBitNumber(i)) + fSelectedCodeIndex.push_back(i); + } +} + +//______________________________________________________________________________ +void TMemStat::MakeStackArray() +{ + // PRIVATE: make code index accoring tbit mask + + if (!fManager) + return; + + delete fStackSummary; + fStackSummary = new TInfoStamp(); + + fSelectedStackIndex.clear(); + + const size_t csize = fManager->fStackVector.size(); + for (size_t i = 0; i < csize; ++i) { + if (fSelectedStackBitmap->TestBitNumber(i)) { + fSelectedStackIndex.push_back(i); + const TStackInfo &info = fManager->fStackVector[i]; + fStackSummary->fTotalAllocCount += info.fCurrentStamp.fTotalAllocCount; + fStackSummary->fTotalAllocSize += info.fCurrentStamp.fTotalAllocSize; + fStackSummary->fAllocCount += info.fCurrentStamp.fAllocCount; + fStackSummary->fAllocSize += info.fCurrentStamp.fAllocSize; + } + } +} + +//______________________________________________________________________________ +void TMemStat::PrintCode(Int_t nentries) const +{ + // Print information about n selected functions + // If the number of function selected is bigger than number n + // the only top (sorted accoring some creteria,) n are displayed + // e.g draw.SortCode(TMemStat::kAllocSize,TMemStat::kCurrent); + if (fSelectedCodeIndex.empty() || !fManager) + return; + + UIntVector_t::const_iterator iter = max((fSelectedCodeIndex.end() - nentries), fSelectedCodeIndex.begin()); + UIntVector_t::const_iterator iter_end = fSelectedCodeIndex.end(); + for (; iter != iter_end; ++iter) + fManager->fCodeInfoArray[*iter].Print(); +} + +//______________________________________________________________________________ +void TMemStat::PrintStack(Int_t nentries, UInt_t deep) const +{ + // Print information about n selected stack traces + // If the number of function selected is bigger than number n + // the only top (sorted accoring some creteria,) n are displayed + // e.g draw.SortCode(TMemStat::kAllocSize,TMemStat::kCurrent); + if (fSelectedStackIndex.empty()) + return; + + UIntVector_t::const_iterator iter = max((fSelectedStackIndex.end() - nentries), fSelectedStackIndex.begin()); + UIntVector_t::const_iterator iter_end = fSelectedStackIndex.end(); + for (; iter != iter_end; ++iter) + PrintStackWithID(*iter, deep); + + cout << "Summary for selected:" << endl; + ios::fmtflags old_flags(cout.flags(ios::left)); + fStackSummary->Print(); + cout.flags(old_flags); +} + +//______________________________________________________________________________ +void TMemStat::PrintStackWithID(UInt_t _id, UInt_t _deep) const +{ + // print stack information for code with ID + if (!fManager) + return; + + _deep = !_deep ? fStackDeep : _deep; + + const TStackInfo &infoStack = fManager->fStackVector[_id]; + cout << infoStack << endl; + + ios::fmtflags old_flags(cout.flags(ios::left)); + for (UInt_t icode = 0, counter = 0; icode < infoStack.fSize; ++icode) { + const TCodeInfo &infoCode(fManager->fCodeInfoArray[infoStack.fSymbolIndexes[icode]]); + if (!EnabledCode(infoCode)) + continue; + cout + << setw(5) << icode + << infoCode << endl; + ++counter; + if (counter >= _deep) + break; + } + cout.flags(old_flags); +} + +//______________________________________________________________________________ +Bool_t TMemStat::EnabledCode(const TCodeInfo &info) const +{ + // Private function + // disable printing of the predefined code sequence + if (info.fLib.Contains("libMemStat.so")) + return kFALSE; + if (info.fFunction.Contains("operator new")) + return kFALSE; + if (info.fFunction.Contains("TMethodCall::Execute")) + return kFALSE; + if (info.fFunction.Contains("Cint::G__CallFunc::Exec")) + return kFALSE; + if (info.fFunction.Contains("Cint::G__ExceptionWrapper")) + return kFALSE; + if (info.fFunction.Sizeof() <= 1) + return kFALSE; + + for (Int_t i = 0; i < fDisablePrintLib.GetEntries(); ++i) { + TObjString * str = (TObjString*)fDisablePrintLib.At(i); + if (str && info.fLib.Contains(str->String().Data())) + return kFALSE; + } + + for (Int_t i = 0; i < fDisablePrintCode.GetEntries(); ++i) { + TObjString * str = (TObjString*)fDisablePrintCode.At(i); + if (str && info.fFunction.Contains(str->String().Data())) + return kFALSE; + } + + return kTRUE; +} + +//______________________________________________________________________________ +TObjArray *TMemStat::MakeGraphCode(StatType statType, Int_t nentries) +{ + // make array of graphs + + if (fArray) { + fArray->Delete(); + delete fArray; + } + fArray = new TObjArray(nentries); + + fArrayIndexes.clear(); + fArrayIndexes.resize(nentries); + + Int_t count = 0; + Double_t xmin = 0, xmax = 0, ymin = 0, ymax = 0; + Int_t first = TMath::Max(static_cast<Int_t>(fSelectedCodeIndex.size()) - nentries, 0); + Double_t cxmax, cymax; + for (Int_t i = fSelectedCodeIndex.size() - 1; i > first; --i) { + TGraph * gr = MakeGraph(statType, fSelectedCodeIndex[i], TInfoStamp::kCode, cxmax, cymax); + if (!gr) + continue; + TCodeInfo &cinfo = fManager->fCodeInfoArray[fSelectedCodeIndex[i]]; + if (cinfo.fFunction.Length() > 0) { + TString str(cinfo.fFunction); + if ((UInt_t)(str.Length()) > fMaxStringLength) + str.Resize(fMaxStringLength); + gr->SetName(str); + } + ++count; + gr->SetLineColor(count % 5 + 1); + + fArrayIndexes[fArray->GetEntries()] = -fSelectedCodeIndex[i]; + fArray->AddLast(gr); + if (xmin == xmax) { + xmin = gr->GetXaxis()->GetXmin(); + xmax = cxmax; + ymin = gr->GetYaxis()->GetXmin(); + ymax = cymax; + } else { + xmin = min(xmin, gr->GetXaxis()->GetXmin()); + xmax = max(xmax, cxmax); + ymin = min(ymin, gr->GetYaxis()->GetXmin()); + ymax = max(ymax, cymax); + } + } + for (Int_t i = 0;i < fArray->GetEntries(); ++i) { + TGraph * gr = (TGraph*)fArray->At(i); + gr->GetXaxis()->SetLimits(xmin, xmax); + gr->GetYaxis()->SetLimits(ymin, ymax); + } + return fArray; +} + +//______________________________________________________________________________ +TObjArray *TMemStat::MakeGraphStack(StatType statType, Int_t nentries) +{ + // make array of graphs + + if (fArray) { + fArray->Delete(); + delete fArray; + } + fArray = new TObjArray(nentries); + + fArrayIndexes.clear(); + fArrayIndexes.resize(nentries); + + Int_t count = 0; + Double_t xmin = 0, xmax = 0, ymin = 0, ymax = 0; + const Int_t first = TMath::Max(static_cast<int>(fSelectedStackIndex.size()) - nentries, 0); + Double_t cxmax(0); + Double_t cymax(0); + for (Int_t i = fSelectedStackIndex.size() - 1; i > first; --i) { + TGraph * gr = MakeGraph(statType, fSelectedStackIndex[i], TInfoStamp::kStack, cxmax, cymax); + if (!gr) + continue; + TStackInfo &infoStack = fManager->fStackVector[(fSelectedStackIndex[i])]; + for (UInt_t icode = 0; icode < infoStack.fSize; icode++) { + TCodeInfo &infoCode = fManager->fCodeInfoArray[infoStack.fSymbolIndexes[icode]]; + if (EnabledCode(infoCode)) { + if (infoCode.fFunction) { + TString str(infoCode.fFunction); + if ((UInt_t)(str.Length()) > fMaxStringLength) str.Resize(fMaxStringLength); + gr->SetName(str); + gr->SetUniqueID(fSelectedStackIndex[i]); + } + break; + } + } + ++count; + gr->SetLineColor(count % 5 + 1); + gr->SetMarkerColor(count % 5 + 1); + gr->SetMarkerStyle(20 + count % 5); + gr->SetMarkerSize(0.15); + fArrayIndexes[fArray->GetEntries()] = fSelectedStackIndex[i]; + fArray->AddLast(gr); + if (xmin == xmax) { + xmin = gr->GetXaxis()->GetXmin(); + xmax = cxmax; + ymin = gr->GetYaxis()->GetXmin(); + ymax = cymax; + } else { + xmin = min(xmin, gr->GetXaxis()->GetXmin()); + xmax = max(xmax, cxmax); + ymin = min(ymin, gr->GetYaxis()->GetXmin()); + ymax = max(ymax, cymax); + } + } + + for (Int_t i = 0; i < fArray->GetEntries(); ++i) { + TGraph * gr = (TGraph*)fArray->At(i); + gr->GetXaxis()->SetLimits(xmin, xmax); + gr->GetYaxis()->SetLimits(ymin, ymax); + } + + return fArray; +} + +//______________________________________________________________________________ +TGraph *TMemStat::MakeGraph(StatType statType, Int_t id, Int_t type, Double_t &xmax, Double_t &ymax) +{ + // Make graph + + if (!fTree) + return 0; + + string sWhat; + string sWhatName; + switch (statType) { + case kTotalAllocCount: + sWhat = "fStampVector.fTotalAllocCount:fStampVector.fStampNumber"; + sWhatName = "TotalAllocCount"; + break; + case kAllocCount: + sWhat = "fStampVector.fAllocCount:fStampVector.fStampNumber"; + sWhatName = "AllocCount"; + break; + case kTotalAllocSize: + sWhat = "fStampVector.fTotalAllocSize/1000000.:fStampVector.fStampNumber"; + sWhatName = "TotalAllocSize (MBy)"; + break; + case kAllocSize: + sWhat = "fStampVector.fAllocSize/1000000.:fStampVector.fStampNumber"; + sWhatName = "AllocSize (MBy)"; + break; + case kUndef: + // TODO: check this case; in originalk code it wasn't handled + break; + } + ostringstream ssWhere; + ssWhere << "fStampVector.fID==" << id << "&&fStampVector.fStampType==" << type; + + const Int_t entries = fTree->Draw(sWhat.c_str(), ssWhere.str().c_str(), "goff"); + if (entries <= 0) + return 0; + + const Int_t maxStamp = fManager->fStampNumber; + + Float_t *x = new Float_t[maxStamp]; + Float_t *y = new Float_t[maxStamp]; + xmax = 0; + ymax = 0; + Float_t last = 0; + for (Int_t i = 0, counter = 0; i < maxStamp; ++i) { + x[i] = i; + y[i] = last; + if (y[i] > ymax) ymax = y[i]; + if (x[i] > xmax) xmax = x[i]; + if (counter >= entries) + continue; + if (fTree->GetV2()[counter] > i) { + y[i] = last; + } else { + y[i] = fTree->GetV1()[counter]; + last = y[i]; + ++counter; + } + } + TGraph * graph = new TGraph(maxStamp, x, y); + graph->GetXaxis()->SetTitle("StampNumber"); + graph->GetYaxis()->SetTitle(sWhatName.c_str()); + return graph; +} + +//______________________________________________________________________________ +void TMemStat::MakeStampsText() +{ + // Make a text description of the stamps + // create a array of TText objects + if (!fArrayGraphics) + fArrayGraphics = new TObjArray(); + + const Int_t nentries = fTree->GetEntries(); + Int_t stampNumber(0); + TObjString *pnameStamp(NULL); + TTimeStamp *ptimeStamp(NULL); + fTree->SetBranchAddress("StampTime.", &ptimeStamp); + fTree->SetBranchAddress("StampName.", &pnameStamp); + fTree->SetBranchAddress("StampNumber", &stampNumber); + + for (Int_t i = 0; i < nentries; ++i) { + fTree->GetBranch("StampTime.")->GetEntry(i); + fTree->GetBranch("StampName.")->GetEntry(i); + fTree->GetBranch("StampNumber")->GetEntry(i); + char chname[1000]; + if (pnameStamp->GetString().Contains("autoStamp")) { + sprintf(chname, " "); + } else { + sprintf(chname, "%s %d", pnameStamp->GetString().Data(), ptimeStamp->GetTime()); + } + TText *ptext = new TText(stampNumber, 0, chname); + fArrayGraphics->AddLast(ptext); + TLine * pline = new TLine(stampNumber, 0, stampNumber, 1); + fArrayGraphics->AddLast(pline); + } +} + +//______________________________________________________________________________ +void TMemStat::ProcessOption(Option_t *option) +{ + // PRIVATE function + // process user option string for printing + + TString str(option); + TString delim(" "); + TObjArray *tokens = str.Tokenize(delim); + for (Int_t i = 0; i < tokens->GetEntriesFast() - 1; ++i) { + TObjString *strTok = (TObjString*)tokens->At(i); + TObjString *strNum = (i < tokens->GetEntriesFast()) ? (TObjString*)tokens->At(i + 1) : 0; + + if (strNum && strNum->String().IsDigit()) { + if (strTok->String().Contains("sortstat")) { + Int_t val = strNum->String().Atoi(); + if (val > 3) { + Error("SetOption", Form("Invalid value for sortstat %d", val)); + val = 3; + } + fSortStat = (TMemStat::StatType)val; + } + if (strTok->String().Contains("sortstamp")) { + Int_t val = strNum->String().Atoi(); + if (val > 2) { + Error("SetOption", Form("Invalid value for sortstamp %d", val)); + val = 0; + } + fSortStamp = (TMemStat::StampType)val; + } + + if (strTok->String().Contains("order")) { + Int_t val = strNum->String().Atoi(); + if (val > 1) { + Error("SetOption", Form("Invalid sorting value", val)); + val = 0; + } + fOrder = (val > 0); + } + if (strTok->String().Contains("sortdeep")) { + fSortDeep = strNum->String().Atoi(); + } + if (strTok->String().Contains("stackdeep")) { + fStackDeep = strNum->String().Atoi(); + } + if (strTok->String().Contains("maxlength")) { + fMaxStringLength = strNum->String().Atoi(); + } + } + } + char currentOption[1000]; + sprintf(currentOption, "order %d sortstat %d sortstamp %d sortdeep %d stackdeep %d maxlength %d", + fOrder, fSortStat, fSortStamp, fSortDeep, fStackDeep, fMaxStringLength); + fOption = currentOption; + if (str.Contains("?")) { + printf("Options : %s\n", fOption.Data()); + printf("order : 0 - increasing 1 - decreasing\n"); + printf("sortstat : 0 - TotalAllocCount 1 - TotalAlocSize 2 - AllocCount 3 - AllocSize\n"); + printf("sortstamp : 0 - Current 1 - MaxSize 2 - MaxCount\n"); + printf("sortdeep : (0-inf) number of info to print\n"); + printf("stackdeep : (0-inf) deepnes of stack\n"); + printf("maxlength : (0-inf) maximal length of function (truncation after maxlength)"); + } + + delete tokens; +} + +//______________________________________________________________________________ +void TMemStat::MakeReport(const char * lib, const char *fun, Option_t* option, const char *fileName) +{ + // make report for library + + // reset selection + SelectCode(NULL, NULL, TMemStat::kOR); + SelectStack(TMemStat::kOR); + // + SelectCode(lib, fun, TMemStat::kAND); + SelectStack(TMemStat::kAND); + if (option) + ProcessOption(option); + SortCode(fSortStat, fSortStamp); + SortStack(fSortStat, fSortStamp); + + // Redirecting the output if needed + if (strlen(fileName) > 0) + gSystem->RedirectOutput(fileName, "w"); + + Report(); + + if (strlen(fileName) > 0) + gSystem->RedirectOutput(0); +} + +//______________________________________________________________________________ +void TMemStat::MakeHisMemoryTime() +{ + // Make dump of memory usage versus time + + fTreeSys->Draw("Mem3:StampTime.fSec>>hhh", "", "goff*"); + if (!gROOT->FindObject("hhh")) + return ; + + TH1* his3 = (TH1*)gROOT->FindObject("hhh")->Clone("Virtual Memory"); + his3->SetDirectory(0); + delete gROOT->FindObject("hhh"); + + fTreeSys->Draw("Mem2:StampTime.fSec>>hhh", "", "goff*"); + if (!gROOT->FindObject("hhh")) + return ; + + TH1* his2 = (TH1*)gROOT->FindObject("hhh")->Clone("Residual Memory"); + his2->SetDirectory(0); + delete gROOT->FindObject("hhh"); + + fTreeSys->Draw("CurrentStamp.fAllocSize/1000000.:StampTime.fSec>>hhh", "", "goff*"); + if (!gROOT->FindObject("hhh")) + return ; + + TH1* hism = (TH1*)gROOT->FindObject("hhh")->Clone("Allocated Memory"); + hism->SetDirectory(0); + delete gROOT->FindObject("hhh"); + + his3->GetXaxis()->SetTimeDisplay(1); + his3->SetMarkerColor(2); + his2->SetMarkerColor(3); + hism->SetMarkerColor(4); + his3->Draw(); + his2->Draw("same"); + hism->Draw("same"); +} + +//______________________________________________________________________________ +void TMemStat::MakeHisMemoryStamp(Int_t /*topDiff*/) +{ + //draw histogram of memory usage as function of stamp name + // NOT IMPLEMENTED YET + const Int_t entries = fTreeSys->Draw("Mem3", "Mem3>0", ""); + DoubleVector_t diff(entries - 1); + for (Int_t i = 0; i < entries - 1; ++i) { + diff[i] = fTreeSys->GetV1()[i+1] - fTreeSys->GetV1()[i]; + } + IntVector_t indexes(entries - 1); + TMath::Sort(entries - 1, &diff[0], &indexes[0], kFALSE); +} + +//______________________________________________________________________________ +void TMemStat::GetFillSelection(Selection_t *_Container, ESelection _Selection) const +{ + if ( !_Container || !fManager) + return; + + transform( fManager->fCodeInfoArray.begin(), + fManager->fCodeInfoArray.end(), + inserter(*_Container, _Container->begin()), + bind2nd(SFillSelection(), _Selection) ); +} diff --git a/misc/memstat/src/TMemStatDepend.cxx b/misc/memstat/src/TMemStatDepend.cxx new file mode 100644 index 00000000000..3e58e4fd560 --- /dev/null +++ b/misc/memstat/src/TMemStatDepend.cxx @@ -0,0 +1,211 @@ +// @(#)root/new:$Name$:$Id$ +// Author: M.Ivanov 18/06/2007 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +//______________________________________________________________________________ +// +// TMemStatDepend - non standard C++ functions - Needed to make +// memory statistic (Used by TMemStatManager) +// +// To be implemented for differnt platoforms. +//______________________________________________________________________________ + + +//STD +#include <string> +#include <vector> +// ROOT +#include "TString.h" +// API +#include <malloc.h> +#include <execinfo.h> +#include <cxxabi.h> +// MemStat +#include "TMemStatDepend.h" + +// This is a global variable set at MSManager init time. +// It marks the highest used stack address. +void *g_global_stack_end = NULL; + +#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__) +// Comment from Anar: +// HACK: there is an ugly bug in gcc (Bug#8743): http://gcc.gnu.org/bugzilla/show_bug.cgi?id=8743 +// "receiving result from __builtin_return_address() beyond stack top causes segfault" +// NOTE that __builtin_return_address should only be used with a non-zero argument for +// debugging purposes. So we use it on our risk. +// A workaround: +// This means the address is out of range. Note that for the +// toplevel we see a frame pointer with value NULL which clearly is out of range. +// NOTE 2: With gcc 4.1, some optimization levels (e.g., -O, -Os, -O2) have started to imply -fomit-frame-pointer. +// One should use GCC builtin function with -fno-omit-frame-pointer option. +#define G__builtin_return_address(N) \ + ((__builtin_frame_address(N) == NULL) || \ + (__builtin_frame_address(N) >= g_global_stack_end) || \ + (__builtin_frame_address(N) < __builtin_frame_address(0))) ? \ + NULL : __builtin_return_address(N) +// __builtin_return_address(0) yields the address to which the current +// function will return. __builtin_return_address(1) yields the address to +// which the caller will return, and so on up the stack. +#define _RET_ADDR(x) case x: return G__builtin_return_address(x); + +#endif + +using namespace std; + +ClassImp(TMemStatDepend) + + +//______________________________________________________________________________ +static void *return_address(int _frame) +{ + // we have a limit on the depth = 35 + switch (_frame) { + _RET_ADDR(0);_RET_ADDR(1);_RET_ADDR(2);_RET_ADDR(3);_RET_ADDR(4);_RET_ADDR(5);_RET_ADDR(6); + _RET_ADDR(7);_RET_ADDR(8);_RET_ADDR(9);_RET_ADDR(10);_RET_ADDR(11);_RET_ADDR(12);_RET_ADDR(13); + _RET_ADDR(14);_RET_ADDR(15);_RET_ADDR(16);_RET_ADDR(17);_RET_ADDR(18);_RET_ADDR(19);_RET_ADDR(20); + _RET_ADDR(21);_RET_ADDR(22);_RET_ADDR(23);_RET_ADDR(24);_RET_ADDR(25);_RET_ADDR(26);_RET_ADDR(27); + _RET_ADDR(28);_RET_ADDR(29);_RET_ADDR(30);_RET_ADDR(31);_RET_ADDR(32);_RET_ADDR(33);_RET_ADDR(34); + _RET_ADDR(35); + default: + return NULL; + } +} + +//______________________________________________________________________________ +size_t builtin_return_address(void **_Container, size_t _limit) +{ + size_t i(0); + void *addr; + for (i = 0; (i < _limit) && (addr = return_address(i)); ++i) + _Container[i] = addr; + return i; +} + +//______________________________________________________________________________ +TMemStatDepend::MallocHookFunc_t TMemStatDepend::GetMallocHook() +{ + //malloc function getter + + return __malloc_hook; +} + +//______________________________________________________________________________ +TMemStatDepend::FreeHookFunc_t TMemStatDepend::GetFreeHook() +{ + //free function getter + + return __free_hook; +} + +//______________________________________________________________________________ +void TMemStatDepend::SetMallocHook(MallocHookFunc_t p) +{ + // Set pointer to function replacing alloc function + + __malloc_hook = p; +} + +//______________________________________________________________________________ +void TMemStatDepend::SetFreeHook(FreeHookFunc_t p) +{ + // Set pointer to function replacing free function + + __free_hook = p; +} + +//______________________________________________________________________________ +size_t TMemStatDepend::Backtrace(void **trace, size_t dsize, Bool_t _bUseGNUBuildinBacktrace) +{ + // Get the backtrace + // dsize - maximal deepnes of stack information + // trace - array of pointers + // return value = min(stack deepnes, dsize) + + if( _bUseGNUBuildinBacktrace ) + { +#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__) + // Initialize the stack end variable. + return builtin_return_address(trace, dsize); +#endif + return 0; + } + return backtrace(trace, dsize); +} + +//______________________________________________________________________________ +char** TMemStatDepend::BacktraceSymbols(void **trace, size_t size) +{ +#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__) + return backtrace_symbols(trace, size); +#endif + return 0; +} + +//______________________________________________________________________________ +void TMemStatDepend::GetSymbols(void *_pFunction, + TString &_strInfo, TString &_strLib, TString &_strFun, TString &/*_strLine*/) +{ + // get the name of the function and library + +#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__) + char ** code = backtrace_symbols(&_pFunction, 1); + if (!code || !code[0]) + return; + const string codeInfo(code[0]); + // it is the responsibility of the caller to free that pointer + free(code); + + // information about the call + _strInfo = codeInfo.c_str(); + + // Resolving a libary name + const string::size_type pos_begin = codeInfo.find('('); + if (string::npos == pos_begin) { + _strLib = codeInfo; + return; + } + _strLib = codeInfo.substr(0, pos_begin); + + // Resolving a function name + string::size_type pos_end = codeInfo.find('+', pos_begin); + if (string::npos == pos_end) { + pos_end = codeInfo.find(')', pos_begin); + if (string::npos == pos_end) + return; // TODO: log me! + } + const string func(codeInfo.substr(pos_begin + 1, pos_end - pos_begin - 1)); + + // Demangling the function name + int status(0); + char *ch = abi::__cxa_demangle(func.c_str(), 0, 0, &status); + if (!ch) + return; + _strFun = (!status) ? ch : func.c_str(); + // it is the responsibility of the caller to free that pointer + free(ch); +#endif +} + +//______________________________________________________________________________ +void TMemStatDepend::Demangle(char *codeInfo, TString &str) +{ + // get the name of the function and library + +#if defined(R__GNU) && (defined(R__LINUX) || defined(R__HURD)) && !defined(__alpha__) + int status = 0; + char *ch = abi::__cxa_demangle(codeInfo, 0, 0, &status); + if (ch) { + str = ch; + free(ch); + } else { + str = "unknown"; + } +#endif +} diff --git a/misc/memstat/src/TMemStatDrawDlg.cxx b/misc/memstat/src/TMemStatDrawDlg.cxx new file mode 100644 index 00000000000..482cb506d69 --- /dev/null +++ b/misc/memstat/src/TMemStatDrawDlg.cxx @@ -0,0 +1,240 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: Anar Manafov (A.Manafov@gsi.de) 31/05/2008 + +// STD +#include <sstream> +#include <algorithm> +// ROOT +#include "TGLabel.h" +#include "TGComboBox.h" +#include "TGNumberEntry.h" +#include "TGButton.h" +#include "TCanvas.h" +#include "TRootEmbeddedCanvas.h" +// MemStat +#include "TMemStat.h" +#include "TMemStatDrawDlg.h" +#include "TMemStatResource.h" + +using namespace std; + +//______________________________________________________________________________ +struct SFill : public binary_function<string, TGComboBox*, bool> +{ + bool operator()(const string &val, TGComboBox* box) const + { + if (!box) + return false;//parametr is a NULL pointer" + + box->AddEntry(val.c_str(), box->GetNumberOfEntries()); + return true; + } +}; + +//______________________________________________________________________________ +TMemStatDrawDlg::TMemStatDrawDlg(const TGWindow *p, const TGWindow *main, TMemStat *MemStat): + fMain(NULL), + fMemStat(MemStat), + fboxOrder(NULL), + fboxSortStat(NULL), + fboxSortStamp(NULL), + fNmbStackDeep(NULL), + fNmbSortDeep(NULL), + fNmbMaxLength(NULL), + fEc(NULL) +{ + // Create a dialog window. A dialog window pops up with respect to its + // "main" window. + + fMain = new TGTransientFrame(p, main, 800, 400, kVerticalFrame | kFixedSize); + // use hierarchical cleaning + fMain->SetCleanup(kDeepCleanup); + fMain->Connect("CloseWindow()", "TMemStatDrawDlg", this, "CloseWindow()"); + fMain->DontCallClose(); // to avoid double deletions. + PlaceCtrls(fMain); + + // position relative to the parent's window + fMain->CenterOnParent(); + + fMain->MapSubwindows(); + fMain->Resize(); + + //TODO: Change the title of the dialog + fMain->SetWindowName("Draw TMemStat"); + fMain->MapWindow(); +} + +//______________________________________________________________________________ +TMemStatDrawDlg::~TMemStatDrawDlg() +{ + // Delete test dialog widgets. + + fMain->DeleteWindow(); // deletes fMain +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::CloseWindow() +{ + // Called when window is closed via the window manager. + + delete this; +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::PlaceCtrls(TGCompositeFrame *frame) +{ + TGCompositeFrame *cont = new TGCompositeFrame(frame, 800, 400, kHorizontalFrame | kFitWidth | kFitHeight); + frame->AddFrame(cont, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY | kLHintsExpandX, 2, 2, 2, 2)); + + TGCompositeFrame *contR = new TGCompositeFrame(cont, 200, 200, kVerticalFrame | kFitWidth | kFitHeight); + cont->AddFrame(contR, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY, 2, 2, 2, 2)); + + StringVector_t values; + // Order + values.push_back("increasing"); + values.push_back("decreasing"); + PlaceLBoxCtrl(contR, &fboxOrder, "Order: ", values, resCBoxOrder); + // Sort Stat + values.clear(); + values.push_back("TotalAllocCount"); + values.push_back("TotalAlocSize"); + values.push_back("AllocCount"); + values.push_back("AllocSize"); + PlaceLBoxCtrl(contR, &fboxSortStat, "Sort stat: ", values, resCBoxSortStat); + // Sort Stamp + values.clear(); + values.push_back("Current"); + values.push_back("MaxSize"); + values.push_back("MaxCount"); + PlaceLBoxCtrl(contR, &fboxSortStamp, "Sort stamp: ", values, resCBoxSortStamp); + // sortdeep and stackdeep + PlaceDeepCtrl(contR); + + // a Draw button + TGTextButton *btnDraw = new TGTextButton(contR); + btnDraw->Connect("Clicked()", "TMemStatDrawDlg", this, "HandleDrawMemStat()"); + btnDraw->SetText("Draw"); + contR->AddFrame(btnDraw, + new TGLayoutHints(kLHintsCenterX | kLHintsExpandX, 10, 10, 10, 10)); + + // a Canvas + PlaceEmbeddedCanvas(cont); +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::PlaceLBoxCtrl(TGCompositeFrame *frame, TGComboBox **box, + const string &Label, const StringVector_t &Vealues, Int_t resource) +{ + TGHorizontalFrame *horz = new TGHorizontalFrame(frame); + frame->AddFrame(horz, new TGLayoutHints(kLHintsExpandX)); + // text description + TGLabel *lbl = new TGLabel(horz, Label.c_str()); + horz->AddFrame(lbl, + new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 2, 2, 2, 2)); + + // a list box of stamps + *box = new TGComboBox( horz, resource ); + (*box)->Resize(120, 20); + horz->AddFrame((*box), new TGLayoutHints(kLHintsRight, 2, 2, 2, 2)); + + // filling Combo box with values + for_each(Vealues.begin(), Vealues.end(), bind2nd(SFill(), (*box))); + + (*box)->Select(0); +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::PlaceDeepCtrl(TGCompositeFrame *frame) +{ + // create and layout "Deep" controls + + // deep of information + TGGroupFrame *ContDeep = new TGGroupFrame(frame, "Deepnes", kVerticalFrame | kFitWidth | kFitHeight); + frame->AddFrame(ContDeep, new TGLayoutHints(kLHintsExpandX)); + + // A "Deep" frame + TGHorizontalFrame *horz0 = new TGHorizontalFrame(ContDeep); + ContDeep->AddFrame(horz0, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY)); + // ------ Stack Deep + // text description + TGLabel *lblStackDeep = new TGLabel(horz0, "Stack deep:"); + horz0->AddFrame(lblStackDeep, new TGLayoutHints(kLHintsLeft | kLHintsCenterY)); + // number entry box for specifying the stack deepness + fNmbStackDeep = new TGNumberEntry(horz0, fMemStat->fStackDeep, 1, resNmbStackDeep, TGNumberFormat::kNESInteger, + TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 1, 50); + horz0->AddFrame(fNmbStackDeep, new TGLayoutHints( kLHintsRight, 2, 2, 2, 2)); + fNmbStackDeep->Resize(100, 20); + + // ------ Sort Deep + TGHorizontalFrame *horz1 = new TGHorizontalFrame(ContDeep); + ContDeep->AddFrame(horz1, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY)); + // text description + TGLabel *LabSortDeep = new TGLabel(horz1, "Sort deep:"); + horz1->AddFrame(LabSortDeep, new TGLayoutHints(kLHintsLeft | kLHintsCenterY)); + // number entry box for specifying the number of stamps + fNmbSortDeep = new TGNumberEntry(horz1, fMemStat->fStackDeep, 1, resNmbSortDeep, TGNumberFormat::kNESInteger, + TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 1, 50); + horz1->AddFrame(fNmbSortDeep, new TGLayoutHints( kLHintsRight, 2, 2, 2, 2)); + fNmbSortDeep->Resize(100, 20); + + // ------ Max lenthg + TGHorizontalFrame *horz2 = new TGHorizontalFrame(ContDeep); + ContDeep->AddFrame(horz2, new TGLayoutHints(kLHintsExpandX | kLHintsCenterY)); + // text description + TGLabel *lbl = new TGLabel(horz2, "Max length:"); + horz2->AddFrame(lbl, new TGLayoutHints(kLHintsLeft | kLHintsCenterY)); + // number entry box for specifying the number of stamps + fNmbMaxLength = new TGNumberEntry(horz2, fMemStat->fStackDeep, 1, resNmbMaxLength, TGNumberFormat::kNESInteger, + TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 1, 500); + horz2->AddFrame(fNmbMaxLength, new TGLayoutHints(kLHintsRight, 2, 2, 2, 2)); + fNmbMaxLength->Resize(100, 20); +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::ReDraw() +{ + if (!fMemStat) + return; + + //"order 0 sortstat 2 sortstamp 1 sortdeep 10 stackdeep 5 maxlength 50" + ostringstream ss; + // order + if (fboxOrder) + ss << "order " << fboxOrder->GetSelected(); + // sort stat + if (fboxSortStat) + ss << " sortstat " << fboxSortStat->GetSelected(); + // sort stamp + if (fboxSortStamp) + ss << " sortstamp " << fboxSortStamp->GetSelected(); + // sort deep + if (fNmbStackDeep) + ss << " sortdeep " << fNmbStackDeep->GetIntNumber(); + // stack deep + if (fNmbSortDeep) + ss << " stackdeep " << fNmbSortDeep->GetIntNumber(); + // max length + if (fNmbMaxLength) + ss << " maxlength " << fNmbMaxLength->GetIntNumber(); + + fMemStat->Draw(ss.str().c_str()); + fEc->GetCanvas()->Modified(); + fEc->GetCanvas()->Update(); +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::HandleDrawMemStat() +{ + ReDraw(); +} + +//______________________________________________________________________________ +void TMemStatDrawDlg::PlaceEmbeddedCanvas(TGCompositeFrame *frame) +{ + if (fEc) + return; + + fEc = new TRootEmbeddedCanvas("ec", frame, 200, 200); + frame->AddFrame(fEc, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY)); + fEc->GetCanvas()->SetBorderMode(0); +} diff --git a/misc/memstat/src/TMemStatHelpers.cxx b/misc/memstat/src/TMemStatHelpers.cxx new file mode 100644 index 00000000000..31206f7fc23 --- /dev/null +++ b/misc/memstat/src/TMemStatHelpers.cxx @@ -0,0 +1,51 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: Anar Manafov (A.Manafov@gsi.de) 09/05/2008 + +// STD +#include <iomanip> +#include <sstream> +// ROOT +#include "Rtypes.h" +// Memstat +#include "TMemStatHelpers.h" + +using namespace std; + +//______________________________________________________________________________ +string Memstat::dig2bytes(Long64_t bytes) +{ + // This function creates a string representation of the number of bytes, + // represented as a number in B, kB, MB or GB depending on the value. + // The result is rounded to a sensible number of digits + + ostringstream ss; + ss << fixed; + + if (bytes < 0) { + ss << '-'; + bytes = -bytes; + } + + static const long kB = 1024l; + static const long MB = kB * kB; + static const long GB = MB * kB; + + if (bytes < kB) + ss << bytes << " B"; + else if (bytes < (10l * kB)) + ss << setprecision(2) << ((double)bytes / (float)kB) << " kB"; + else if (bytes < (100l * kB)) + ss << setprecision(1) << ((double)bytes / (float)kB) << " kB"; + else if (bytes < MB) + ss << setprecision(0) << ((double)bytes / (float)kB) << " kB"; + else if (bytes < (10l * MB)) + ss << setprecision(2) << ((double)bytes / (float)MB) << " MB"; + else if (bytes < (100l * MB)) + ss << setprecision(1) << ((double)bytes / (float)MB) << " MB"; + else if (bytes < GB) + ss << setprecision(0) << ((double)bytes / (float)MB) << " MB"; + else + ss << setprecision(2) << ((double)bytes / (float)GB) << " GB"; + + return ss.str(); +} diff --git a/misc/memstat/src/TMemStatInfo.cxx b/misc/memstat/src/TMemStatInfo.cxx new file mode 100644 index 00000000000..cfd172d6e0c --- /dev/null +++ b/misc/memstat/src/TMemStatInfo.cxx @@ -0,0 +1,294 @@ +// @(#)root/new:$Name$:$Id$ +// Author: D.Bertini and M.Ivanov 10/08/2000 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +//****************************************************************************// + +/* + Mem Stat information - +. TInfoStamp - counter + fTotalAllocCount; //total number of allocation for stack sequence + fTotalAllocSize; //total size of allocated memory + fAllocCount; //current number of allocation-deallocation + fAllocSize; //current allocated size + TCodeInfo + base code inormation - strings - fFunction and fLib (function desription) + - stamps - + TInfoStamp fLastStamp; // last time stamp info + TInfoStamp fCurrentStamp; // current time stamp info + TInfoStamp fMaxStampSize; // max current size stamp + TInfoStamp fMaxStamp; // max current size stamp + TStackInfo + base stack inormation - array of pointers to Code informations + - stamps - + TInfoStamp fLastStamp; // last time stamp info + TInfoStamp fCurrentStamp; // current time stamp info + TInfoStamp fMaxStampSize; // max current size stamp + TInfoStamp fMaxStamp; // max current size stamp +*/ +// +//****************************************************************************// +// ROOT +#include "Riostream.h" +#include "TObject.h" +// Memstat +#include "TMemStatInfo.h" +#include "TMemStatManager.h" +#include "TMemStatDepend.h" + + +ClassImp(TCodeInfo) +ClassImp(TInfoStamp) +ClassImp(TStackInfo) + +//****************************************************************************// +// TInfoStamp +//****************************************************************************// + +//______________________________________________________________________________ +TInfoStamp::TInfoStamp(): + fTotalAllocCount(0), //total number of allocation for stack sequence + fTotalAllocSize(0), //total size of allocated memory + fAllocCount(0), //current number of allocation-deallocation + fAllocSize(0), //current allocated size + fStampNumber(0), //index of previous + fID(0), //code ID + fStampType(0) +{ +} + +//______________________________________________________________________________ +TInfoStamp::~TInfoStamp() +{ +} + +//______________________________________________________________________________ +void TInfoStamp::Print(Option_t* /*option*/) const +{ + cout << *this << endl; +} + +//______________________________________________________________________________ +std::ostream& operator << (std::ostream &_ostream, const TInfoStamp &_this) +{ + _ostream + << std::setw(fields_length[1]) << "ID" + << std::setw(fields_length[2]) << "Sort" + << std::setw(fields_length[3]) << "TotalCount" + << std::setw(fields_length[4]) << "TotalSize" + << std::setw(fields_length[5]) << "Count" + << std::setw(fields_length[6]) << "Size" << std::endl; + + // Setting a bit nicer formating + // example: instead of 20600000 print 20,600,000 + std::locale loc(""); + std::locale loc_previous = _ostream.imbue(loc); + _ostream.precision(2); + _ostream << std::fixed; + + _ostream + << std::setw(fields_length[1]) << _this.fStampNumber + << std::setw(fields_length[2]) << _this.fID + << std::setw(fields_length[3]) << _this.fTotalAllocCount + << std::setw(fields_length[4]) << Memstat::dig2bytes(_this.fTotalAllocSize) + << std::setw(fields_length[5]) << _this.fAllocCount + << std::setw(fields_length[6]) << Memstat::dig2bytes(_this.fAllocSize); + + _ostream.imbue(loc_previous); + + return _ostream; +} + +//****************************************************************************// +// TCodeInfo +//****************************************************************************// + +//______________________________________________________________________________ +TCodeInfo::TCodeInfo(): + fLastStamp(), + fCurrentStamp(), + fMaxStampSize(), + fMaxStamp(), + fCode(0), + fInfo(0), + fFunction(), + fLib(), + fCodeID(0) +{ + fLastStamp.fStampType = TInfoStamp::kCode; + fCurrentStamp.fStampType = TInfoStamp::kCode; + fMaxStampSize.fStampType = TInfoStamp::kCode; + fMaxStamp.fStampType = TInfoStamp::kCode; +} + +//______________________________________________________________________________ +void TCodeInfo::Inc(Int_t memSize) +{ + fCurrentStamp.Inc(memSize); + if (fCurrentStamp.fAllocCount > fMaxStamp.fAllocCount) + fMaxStamp = fCurrentStamp; + if (fCurrentStamp.fAllocSize > fMaxStampSize.fAllocSize) + fMaxStampSize = fCurrentStamp; +} + +//______________________________________________________________________________ +void TCodeInfo::SetInfo(void *info) +{ + // Get function realname from info descriptor + + char *zero = 0; + fCode = (Long64_t)((char*)info - zero); + TString strLine; + TMemStatDepend::GetSymbols(info, fInfo, fLib, fFunction, strLine); +} + +//______________________________________________________________________________ +void TCodeInfo::Print(Option_t * /*option*/) const +{ + StreemCurrAndMax(cout, *this) << endl; + + cout << fCodeID << "\t" << fInfo.Data() << endl; + cout << fCodeID << "\t" << fLib.Data() << '\t' << fFunction.Data() << endl; +} + +//______________________________________________________________________________ +void TCodeInfo::MakeStamp(Int_t stampNumber) +{ + // make time stamp - only if change + + if (fCurrentStamp.Equal(fLastStamp)) + return; + + TInfoStamp &newStamp = TMemStatManager::GetInstance()->AddStamp(); + fCurrentStamp.fStampNumber = stampNumber; + newStamp = fCurrentStamp; + fLastStamp = newStamp; +} + +//______________________________________________________________________________ +std::ostream& operator << (std::ostream &_ostream, const TCodeInfo &_this) +{ + _ostream + << _this.fFunction.Data() + << '\t' << _this.fLib.Data(); + + return _ostream; +} + + +//****************************************************************************// +// Storage of Stack information +//****************************************************************************// + +//______________________________________________________________________________ +TStackInfo::TStackInfo(): + TObject(), + fSize(0), + fLastStamp(), + fCurrentStamp(), + fMaxStampSize(), + fMaxStamp(), + fNextHash(-1), + fStackSymbols(0), + fSymbolIndexes(0), + fStackID(0) +{ + fLastStamp.fStampType = TInfoStamp::kStack; + fCurrentStamp.fStampType = TInfoStamp::kStack; + fMaxStampSize.fStampType = TInfoStamp::kStack; + fMaxStamp.fStampType = TInfoStamp::kStack; +} + +//______________________________________________________________________________ +void TStackInfo::Init(int stacksize, void **stackptrs, TMemStatManager *manager, Int_t ID) +{ + //Initialize the stack + fStackID = ID; + fSize = stacksize; + fLastStamp.fID = fStackID; // last time stamp info + fCurrentStamp.fID = fStackID; // current time stamp info + + fStackSymbols = new void*[stacksize]; + memcpy(fStackSymbols, stackptrs, stacksize * sizeof(void *)); + fSymbolIndexes = new UInt_t[stacksize]; + + for (Int_t i = 0; i < stacksize; ++i) { + TCodeInfo & cinfo = manager->GetCodeInfo(stackptrs[i]); + if (cinfo.fCode == 0) + cinfo.SetInfo(stackptrs[i]); + + fSymbolIndexes[i] = cinfo.fCodeID; + } +} + +//______________________________________________________________________________ +int TStackInfo::Equal(unsigned int size, void **ptr) +{ + // Return 0 if stack information not equal otherwise return 1. + + if (size != fSize) + return 0; + for (size_t i = 0; i < size; ++i) + if (ptr[i] != fStackSymbols[i]) + return 0; + return 1; +} + +//______________________________________________________________________________ +Bool_t TInfoStamp::Equal(TInfoStamp&stamp) +{ + if (fTotalAllocCount != stamp.fTotalAllocCount) + return kFALSE; + if (fAllocCount != stamp.fAllocCount) + return kFALSE; + return kTRUE; +} + +//______________________________________________________________________________ +void TStackInfo::MakeStamp(Int_t stampNumber) +{ + // make time stamp - only if change + + if (fCurrentStamp.Equal(fLastStamp)) + return; + + TInfoStamp &newStamp = TMemStatManager::GetInstance()->AddStamp(); + fCurrentStamp.fStampNumber = stampNumber; + newStamp = fCurrentStamp; + fLastStamp = newStamp; +} + +//______________________________________________________________________________ +void TStackInfo::Inc(Int_t memSize, TMemStatManager *manager) +{ + fCurrentStamp.Inc(memSize); + if (fCurrentStamp.fAllocCount > fMaxStamp.fAllocCount) + fMaxStamp = fCurrentStamp; + if (fCurrentStamp.fAllocSize > fMaxStampSize.fAllocSize) + fMaxStampSize = fCurrentStamp; + for (UInt_t i = 0; i < fSize; ++i) + manager->fCodeInfoArray[fSymbolIndexes[i]].Inc(memSize); +} + +//______________________________________________________________________________ +void TStackInfo::Dec(int memSize, TMemStatManager *manager) +{ + if (fCurrentStamp.fAllocCount) + fCurrentStamp.fAllocCount -= 1; + fCurrentStamp.fAllocSize -= memSize; + for (UInt_t i = 0; i < fSize; ++i) + manager->fCodeInfoArray[fSymbolIndexes[i]].Dec(memSize); +} + +//______________________________________________________________________________ +std::ostream& operator << (std::ostream &_ostream, const TStackInfo &_this) +{ + return StreemCurrAndMax(_ostream, _this); +} diff --git a/misc/memstat/src/TMemStatManager.cxx b/misc/memstat/src/TMemStatManager.cxx new file mode 100644 index 00000000000..e39f443c8b0 --- /dev/null +++ b/misc/memstat/src/TMemStatManager.cxx @@ -0,0 +1,645 @@ +// @(#)root/new:$Name$:$Id$ +// Author: D.Bertini and M.Ivanov 10/08/2000 -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 + +/************************************************************************* + * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +//****************************************************************************// +/* + + TMemStatManager - manager class + + The current memory statistic is written to the file + + Important information used for visualization + std::vector<TStackInfo> fStackVector; // vector with stack symbols + std::vector<TInfoStamp> fStampVector; // vector of stamp information + std::vector<TTimeStamp> fStampTime; // vector of stamp information + std::vector<TCodeInfo> fCodeInfoArray; // vector with code info + +*/ +//****************************************************************************// + +// STD +#include <cstdio> +#include <string> + +#include <malloc.h> +// ROOT +#include "TSystem.h" +#include "TEnv.h" +#include "TError.h" +#include "Riostream.h" +#include "TObject.h" +#include "TFile.h" +#include "TTree.h" +#include "TObjString.h" +// Memstat +#include "TMemStatDepend.h" +#include "TMemStatInfo.h" +#include "TMemStatManager.h" + +const char * const g_cszFileName("memstat.root"); +const Int_t g_STHashSize(65536); //!current size of the hash table + +ClassImp(TMemStatManager) + +TMemStatManager * TMemStatManager::fgInstance = NULL; + + +//****************************************************************************// +// Global Stack Table +//****************************************************************************// + +TMemStatManager::TMemStatManager(): + TObject(), + fSTHashTable(g_STHashSize, -1), //!pointer to the hash table + fCount(0), //!number of entries in table + fStampNumber(0), //current stamp number + fStackVector(), // vector withstack symbols + fStampVector(), // vector of stamp information + fStampTime(), // vector of stamp information + fCodeInfoArray() , // vector with code info + fCodeInfoMap(), //! map of code information + fDebugLevel(0), //!debug level + fStampCallBack(0), //! call back function to register stamp + fPreviousMallocHook(TMemStatDepend::GetMallocHook()), //! + fPreviousFreeHook(TMemStatDepend::GetFreeHook()), //! + fLastStamp(), //last written stamp + fCurrentStamp(), //current stamp + fAutoStampSize(2000000), //change of size invoking STAMP + fAutoStampN(200000), //change of number of allocation STAMP + fAutoStampDumpSize(50000), //change of number of allocation STAMP + fMinStampSize(100), //minimal cut what will be dumeped to the tree + fSize(65536), //!size of hash table + fLeak(NULL), //!pointer to the hash table + fAllocCount(0), //!number of memory allocation blocks + fMultDeleteTable(), //!pointer to the table + fDumpTree(0), //!tree to dump information + fDumpSysTree(0), //!tree to dump information + fUseGNUBuildinBacktrace(kFALSE) +{ + // Default constructor + + SetBit(kUserDisable, kTRUE); + fStampCallBack = TMemStatManager::SAddStamps; //! call back function + +} + +//______________________________________________________________________________ +void TMemStatManager::Init() +{ + //Initialize MemStat manager - used only for instance + + SetBit(kUserDisable, kTRUE); + + fStampNumber = 0; + fAllocCount = 0; + free_hashtable(); + fLeak = (TMemTable **) malloc(sizeof(void *) * fSize); + fMultDeleteTable.fLeaks = 0; + fMultDeleteTable.fAllocCount = 0; + fMultDeleteTable.fTableSize = 0; + fStackVector.reserve(fSize); // vector withstack symbols + fStampVector.reserve(fSize*10); // vector of stamp information + fCodeInfoArray.reserve(fSize); // vector with code info + fStampTime.reserve(fSize); + fStampTime[0] = TTimeStamp(); + for (int i = 0; i < fSize; ++i) { + fLeak[i] = (TMemTable *) malloc(sizeof(TMemTable)); + fLeak[i]->fAllocCount = 0; + fLeak[i]->fMemSize = 0; + fLeak[i]->fFirstFreeSpot = 0; + fLeak[i]->fTableSize = 0; + fLeak[i]->fLeaks = 0; + } + //Initialize ST table. + fCount = 0; + + SetBit(kUserDisable, kTRUE); +} + +//______________________________________________________________________________ +TMemStatManager* TMemStatManager::GetInstance() +{ + // GetInstance of MemStatManager + // Only instance catch the alloc and free hook + + if (!fgInstance) { + fgInstance = new TMemStatManager; + fgInstance->Init(); + } + return fgInstance; +} + +//______________________________________________________________________________ +void TMemStatManager::Close() +{ + // to be documented + + delete fgInstance; + fgInstance = NULL; +} + +//______________________________________________________________________________ +TMemStatManager::~TMemStatManager() +{ + // Destructor + // if instance is destructed - the hooks are reseted to old hooks + + if (this != TMemStatManager::GetInstance()) + return; + SetBit(kStatDisable); + Disable(); + AddStamps("End"); + DumpTo(Tree, kTRUE, "End"); + DumpTo(SysTree, kTRUE, "End"); + Disable(); + + free_hashtable(); +} + +//______________________________________________________________________________ +void TMemStatManager::Enable() +{ + // Enable hooks + + if (this != GetInstance()) + return; + + // set hook to our functions + TMemStatDepend::SetMallocHook(AllocHook); + TMemStatDepend::SetFreeHook(FreeHook); + SetBit(kUserDisable, kFALSE); +} + +//______________________________________________________________________________ +void TMemStatManager::Disable() +{ + // disble MemStatManager + + if (this != GetInstance()) + return; + + // set hook to our functions + TMemStatDepend::SetMallocHook(fPreviousMallocHook); + TMemStatDepend::SetFreeHook(fPreviousFreeHook); + SetBit(kUserDisable, kTRUE); +} + +//______________________________________________________________________________ +void *TMemStatManager::AllocHook(size_t size, const void* /*caller*/) +{ + // AllocHook + + TMemStatManager* instance = TMemStatManager::GetInstance(); + TMemStatDepend::SetMallocHook(instance->fPreviousMallocHook); + void *p = instance->AddPointer(size); + TMemStatDepend::SetMallocHook(AllocHook); + return p; +} + +//______________________________________________________________________________ +void TMemStatManager::FreeHook(void* ptr, const void* /*caller*/) +{ + // FreeHook + + TMemStatManager* instance = TMemStatManager::GetInstance(); + TMemStatDepend::SetFreeHook(instance->fPreviousFreeHook); + instance->FreePointer(ptr); + TMemStatDepend::SetFreeHook(FreeHook); +} + +//______________________________________________________________________________ +TStackInfo *TMemStatManager::STAddInfo(int size, void **stackptrs) +{ + // Add stack information to table. + // add next stack to table + + const UInt_t currentSize = fStackVector.size(); + if (currentSize >= fStackVector.capacity()) + fStackVector.reserve(2*currentSize + 1); + + fStackVector.push_back(TStackInfo()); + TStackInfo *info = &(fStackVector[currentSize]); + info->Init(size, stackptrs, this, currentSize); + info->fStackID = currentSize; + + //add info to hash table + const int hash = int(info->Hash() % g_STHashSize); + Int_t hashIndex = fSTHashTable[hash]; + TStackInfo *info2 = NULL; + + if (-1 == hashIndex) { + fSTHashTable[hash] = info->fStackID; + } else { + info2 = &fStackVector[hashIndex]; + while (hashIndex >= 0) { + hashIndex = info2->fNextHash; + if (hashIndex >= 0) + info2 = &fStackVector[hashIndex]; + } + info2->fNextHash = info->fStackID; + } + + ++fCount; + fStackVector.push_back(*info); + return info; +} + +//______________________________________________________________________________ +TStackInfo *TMemStatManager::STFindInfo(int size, void **stackptrs) +{ + // Try to find stack info in hash table if doesn't find it will add it. + + const int hash = int(TStackInfo::HashStack(size, (void **)stackptrs) % g_STHashSize); + + if (fSTHashTable[hash] < 0) + return STAddInfo(size, stackptrs); // hash value not in hash table + + Int_t hashIndex = fSTHashTable[hash]; + TStackInfo *info = NULL; + + info = &fStackVector[hashIndex]; + while (hashIndex >= 0) { + if (info->Equal(size, stackptrs) == 1) + return info; // info found + hashIndex = info->fNextHash; + if (hashIndex >= 0) + info = &fStackVector[hashIndex]; + } + return STAddInfo(size, stackptrs); // not found info - create new +} + +//______________________________________________________________________________ +void TMemStatManager::SAddStamps(const char * stampname) +{ + // + // static version add stamps to the list of stamps for changed stacks + // + TMemStatManager *man = GetInstance(); + man->AddStamps(stampname); +} + +//______________________________________________________________________________ +void TMemStatManager::AddStamps(const char * stampname) +{ + // add the stamp to the list of stamps + + const UInt_t ssize = fStackVector.size(); + for (UInt_t i = 0; i < ssize; ++i) { + if (fStackVector[i].fCurrentStamp.fAllocSize > fMinStampSize) + fStackVector[i].MakeStamp(fStampNumber); + } + const UInt_t csize = fCodeInfoArray.size(); + for (UInt_t i = 0; i < csize; ++i) { + if (fCodeInfoArray[i].fCurrentStamp.fAllocSize > fMinStampSize) + fCodeInfoArray[i].MakeStamp(fStampNumber); + } + + fCurrentStamp.fID = -1; + fCurrentStamp.fStampNumber = fStampNumber; + AddStamp() = fCurrentStamp; + + fStampTime[fStampNumber] = TTimeStamp(); + if (fStampVector.size() >= fAutoStampDumpSize || stampname) { + DumpTo(Tree, kTRUE, stampname); + DumpTo(SysTree, kTRUE, stampname); + } + ++fStampNumber; +} + +//______________________________________________________________________________ +TInfoStamp &TMemStatManager::AddStamp() +{ + // add one stamp to the list of stamps + + const UInt_t size = fStampVector.size(); + fStampVector.push_back(TInfoStamp()); + TInfoStamp &stamp = fStampVector[size]; + stamp.fStampNumber = fStampNumber; + return stamp; +} + +//______________________________________________________________________________ +TCodeInfo &TMemStatManager::GetCodeInfo(void *address) +{ + // to be documented + + TCodeInfo *info(NULL); + const UInt_t index = fCodeInfoMap[address]; + if (index > 0) { + info = &(fCodeInfoArray[fCodeInfoMap[address]]); + } else { + const UInt_t size = fCodeInfoArray.size(); + fCodeInfoArray.push_back(TCodeInfo()); + info = &(fCodeInfoArray[size]); + fCodeInfoMap[address] = size; + info->fCodeID = size; + info->fCurrentStamp.fID = info->fCodeID; + info->fLastStamp.fID = info->fCodeID; + } + return *info; +} + +//______________________________________________________________________________ +void TMemStatManager::RehashLeak(int newSize) +{ + // Rehash leak pointers. + + if (newSize <= fSize) + return; + TMemTable **newLeak = (TMemTable **) malloc(sizeof(void *) * newSize); + for (int i = 0; i < newSize; ++i) { + //build new branches + newLeak[i] = (TMemTable *) malloc(sizeof(TMemTable)); + newLeak[i]->fAllocCount = 0; + newLeak[i]->fMemSize = 0; + newLeak[i]->fFirstFreeSpot = 0; + newLeak[i]->fTableSize = 0; + newLeak[i]->fLeaks = 0; + } + for (int ib = 0; ib < fSize; ++ib) { + TMemTable *branch = fLeak[ib]; + for (int i = 0; i < branch->fTableSize; i++) + if (branch->fLeaks[i].fAddress != 0) { + int hash = int(TString::Hash(&branch->fLeaks[i].fAddress, sizeof(void*)) % newSize); + TMemTable *newbranch = newLeak[hash]; + if (newbranch->fAllocCount >= newbranch->fTableSize) { + int newTableSize = + newbranch->fTableSize == + 0 ? 16 : newbranch->fTableSize * 2; + newbranch->fLeaks = + (TMemInfo *) realloc(newbranch->fLeaks, + sizeof(TMemInfo) * newTableSize); + if (!newbranch->fLeaks) { + Error("TMemStatManager::AddPointer", "realloc failure"); + _exit(1); + } + memset(newbranch->fLeaks + newbranch->fTableSize, 0, + sizeof(TMemInfo) * (newTableSize - + newbranch->fTableSize)); + newbranch->fTableSize = newTableSize; + } + memcpy(&newbranch->fLeaks[newbranch->fAllocCount], + &branch->fLeaks[i], sizeof(TMemInfo)); + newbranch->fAllocCount++; + newbranch->fMemSize += branch->fLeaks[i].fSize; + } + free(branch->fLeaks); + free(branch); + } //loop over all old branches and rehash information + free(fLeak); + fLeak = newLeak; + fSize = newSize; +} + +//______________________________________________________________________________ +void *TMemStatManager::AddPointer(size_t size, void *ptr) +{ + // Add pointer to table. + + if (TestBit(kUserDisable) || TestBit(kStatDisable)) { + return malloc(size); + } + + Bool_t status = TestBit(kStatRoutine); + SetBit(kStatRoutine, kTRUE); + + void *p = NULL; + + if (ptr == 0) { + p = malloc(size); + if (!p) { + Error("TMemStatManager::AddPointer", "malloc failure"); + TMemStatManager::GetInstance()->Disable(); + TMemStatManager::GetInstance()->Close(); + _exit(1); + } + } else { + p = realloc((char *) ptr, size); + if (!p) { + Error("TMemStatManager::AddPointer", "realloc failure"); + TMemStatManager::GetInstance()->Disable(); + TMemStatManager::GetInstance()->Close(); + _exit(1); + } + SetBit(kStatRoutine, status); + return p; + } + if (status) { + SetBit(kStatRoutine, status); + return p; + } + + if (!fSize) + Init(); + ++fAllocCount; + if ((fAllocCount / fSize) > 128) + RehashLeak(fSize * 2); + int hash = int(TString::Hash(&p, sizeof(void*)) % fSize); + TMemTable *branch = fLeak[hash]; + branch->fAllocCount++; + branch->fMemSize += size; + + fCurrentStamp.Inc(size); + if ((fCurrentStamp.fTotalAllocCount - fLastStamp.fTotalAllocCount) > fAutoStampN || + (fCurrentStamp.fAllocCount - fLastStamp.fAllocCount) > Int_t(fAutoStampN) || + (fCurrentStamp.fTotalAllocSize - fLastStamp.fTotalAllocSize) > fAutoStampSize || + (fCurrentStamp.fAllocSize - fLastStamp.fAllocSize) > Int_t(fAutoStampSize)) { + AddStamps(); + fLastStamp = fCurrentStamp; + if (fAutoStampN < 0.001*fLastStamp.fTotalAllocCount) fAutoStampN = 1 + UInt_t(0.001 * fLastStamp.fTotalAllocCount); + if (fAutoStampSize < 0.001*fLastStamp.fTotalAllocSize) fAutoStampSize = 1 + UInt_t(0.001 * fLastStamp.fTotalAllocSize); + } + + for (;;) { + for (int i = branch->fFirstFreeSpot; i < branch->fTableSize; ++i) + if (branch->fLeaks[i].fAddress == 0) { + branch->fLeaks[i].fAddress = p; + branch->fLeaks[i].fSize = size; + void *stptr[TStackInfo::kStackHistorySize + 1]; + int stackentries = TMemStatDepend::Backtrace(stptr, TStackInfo::kStackHistorySize, fUseGNUBuildinBacktrace); + TStackInfo *info = STFindInfo(stackentries, stptr); + info->Inc(size, this); + if (info->fCurrentStamp.fStampNumber == 0) { + info->MakeStamp(fStampNumber); // add stamp after each addition + } + branch->fLeaks[i].fStackIndex = info->fStackID; + branch->fFirstFreeSpot = i + 1; + SetBit(kStatRoutine, status); + return p; + } + + int newTableSize = + branch->fTableSize == 0 ? 16 : branch->fTableSize * 2; + branch->fLeaks = + (TMemInfo *) realloc(branch->fLeaks, + sizeof(TMemInfo) * newTableSize); + if (!branch->fLeaks) { + Error("TMemStatManager::AddPointer", "realloc failure (2)"); + _exit(1); + } + memset(branch->fLeaks + branch->fTableSize, 0, sizeof(TMemInfo) * + (newTableSize - branch->fTableSize)); + branch->fTableSize = newTableSize; + } +} + +//______________________________________________________________________________ +void TMemStatManager::FreePointer(void *p) +{ + // Free pointer. + + if (p == 0) + return; + if (TestBit(kUserDisable) || TestBit(kStatDisable)) { + free(p); + return; + } + + const Bool_t status = TestBit(kStatRoutine); + SetBit(kStatRoutine, kTRUE); + + if (status) { + SetBit(kStatRoutine, status); + return; + } + + const int hash = static_cast<int>(TString::Hash(&p, sizeof(void*)) % fSize); + --fAllocCount; + TMemTable *branch = fLeak[hash]; + for (int i = 0; i < branch->fTableSize; i++) { + if (branch->fLeaks[i].fAddress == p) { + branch->fLeaks[i].fAddress = 0; + branch->fMemSize -= branch->fLeaks[i].fSize; + if (i < branch->fFirstFreeSpot) + branch->fFirstFreeSpot = i; + free(p); + TStackInfo *info = + &(fStackVector[branch->fLeaks[i].fStackIndex]); + info->Dec(branch->fLeaks[i].fSize, this); + fCurrentStamp.Dec(branch->fLeaks[i].fSize); + branch->fAllocCount--; + SetBit(kStatRoutine, status); + return; + } + } + // + //if try to delete non existing pointer + //printf("***TMemStatManager::FreePointer: Multiple deletion %8p ** ? \n",p); + // printf("-+-+%8p \n",p); + //free(p); + if (fMultDeleteTable.fTableSize + 1 > fMultDeleteTable.fAllocCount) { + int newTableSize = + fMultDeleteTable.fTableSize == + 0 ? 16 : fMultDeleteTable.fTableSize * 2; + fMultDeleteTable.fLeaks = + (TMemInfo *) realloc(fMultDeleteTable.fLeaks, + sizeof(TMemInfo) * newTableSize); + fMultDeleteTable.fAllocCount = newTableSize; + } + + fMultDeleteTable.fLeaks[fMultDeleteTable.fTableSize].fAddress = 0; + //void *sp = 0; + void *stptr[TStackInfo::kStackHistorySize + 1]; + int stackentries = TMemStatDepend::Backtrace(stptr, TStackInfo::kStackHistorySize, fUseGNUBuildinBacktrace); + TStackInfo *info = STFindInfo(stackentries/*j*/, stptr); + info->Dec(0, this); + fMultDeleteTable.fLeaks[fMultDeleteTable.fTableSize].fStackIndex = + info->fStackID; + fMultDeleteTable.fTableSize++; + SetBit(kStatRoutine, status); +} + +//______________________________________________________________________________ +void TMemStatManager::DumpTo(EDumpTo _DumpTo, Bool_t _clearStamps, const char *_stampName) +{ + //write current status to file + const Bool_t status = TestBit(TMemStatManager::kStatDisable); + SetBit(TMemStatManager::kStatDisable, kTRUE); + if (!fDumpFile.get()) + fDumpFile.reset( TFile::Open(g_cszFileName, "recreate") ); + // + TTimeStamp stamp; + MemInfo_t memInfo; + ProcInfo_t procInfo; + gSystem->GetMemInfo(&memInfo); + gSystem->GetProcInfo(&procInfo); + Float_t memUsage[4] = { memInfo.fMemUsed, memInfo.fSwapUsed, + procInfo.fMemResident*0.001, procInfo.fMemVirtual*0.001 + }; + // No need to delete this pointer + TTimeStamp *ptimeStamp(new TTimeStamp); + // pass ownership to an auto_ptr + auto_ptr<TTimeStamp> ptimeStamp_(ptimeStamp); + + TObjString *pnameStamp = + (_stampName != 0) ? new TObjString(_stampName) : new TObjString(Form("autoStamp%d", fStampNumber)); + // pass ownership to an auto_ptr + auto_ptr<TObjString> pnameStamp_(pnameStamp); + + const TMemStatManager * pmanager = this; + Int_t stampNumber = fStampNumber; + + // pass ownership to an auto_ptr + TInfoStamp *currentStamp(new TInfoStamp(fCurrentStamp)); + // pass ownership to an auto_ptr + auto_ptr<TInfoStamp> currentStamp_(currentStamp); + + TTree *pDumpTo(NULL); + bool bNewTree = false; + switch (_DumpTo) { + case Tree: + if (!fDumpTree) { + fDumpTree = new TTree("MemStat", "MemStat"); + bNewTree = true; + } + pDumpTo = fDumpTree; + break; + case SysTree: + if (!fDumpSysTree) { + fDumpSysTree = new TTree("MemSys", "MemSys"); + bNewTree = true; + } + pDumpTo = fDumpSysTree; + break; + default: // TODO: Log me! + return; + } + + if (bNewTree) { + if (Tree == _DumpTo) + pDumpTo->Branch("Manager", "TMemStatManager", &pmanager); + pDumpTo->Branch("StampTime.", "TTimeStamp", &ptimeStamp); + pDumpTo->Branch("StampName.", "TObjString", &pnameStamp); + pDumpTo->Branch("StampNumber", &stampNumber, "StampNumber/I"); + pDumpTo->Branch("CurrentStamp", "TInfoStamp", ¤tStamp); + pDumpTo->Branch("Mem0", &memUsage[0], "Mem0/F"); + pDumpTo->Branch("Mem1", &memUsage[1], "Mem1/F"); + pDumpTo->Branch("Mem2", &memUsage[2], "Mem2/F"); + pDumpTo->Branch("Mem3", &memUsage[3], "Mem3/F"); + } else { + if (Tree == _DumpTo) + pDumpTo->SetBranchAddress("Manager", &pmanager); + pDumpTo->SetBranchAddress("StampTime.", &ptimeStamp); + pDumpTo->SetBranchAddress("StampName.", &pnameStamp); + pDumpTo->SetBranchAddress("StampNumber", &stampNumber); + pDumpTo->SetBranchAddress("CurrentStamp", ¤tStamp); + pDumpTo->SetBranchAddress("Mem0", &memUsage[0]); + pDumpTo->SetBranchAddress("Mem1", &memUsage[1]); + pDumpTo->SetBranchAddress("Mem2", &memUsage[2]); + pDumpTo->SetBranchAddress("Mem3", &memUsage[3]); + } + + pDumpTo->Fill(); + pDumpTo->AutoSave("Stat"); + if (_clearStamps) + fStampVector.clear(); + SetBit(TMemStatManager::kStatDisable, status); +} diff --git a/misc/memstat/src/TMemViewerGUI.cxx b/misc/memstat/src/TMemViewerGUI.cxx new file mode 100644 index 00000000000..84b46f1ea91 --- /dev/null +++ b/misc/memstat/src/TMemViewerGUI.cxx @@ -0,0 +1,418 @@ +// @(#)root/memstat:$Name$:$Id$ +// Author: M.Ivanov -- Anar Manafov (A.Manafov@gsi.de) 28/04/2008 +/************************************************************************** + * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. * + * * + * Author: The ALICE Off-line Project. * + * Contributors are mentioned in the code where appropriate. * + * * + * Permission to use, copy, modify and distribute this software and its * + * documentation strictly for non-commercial purposes is hereby granted * + * without fee, provided that the above copyright notice appears in all * + * copies and that both the copyright notice and this permission notice * + * appear in the supporting documentation. The authors make no claims * + * about the suitability of this software for any purpose. It is * + * provided "as is" without express or implied warranty. * + **************************************************************************/ + + +/////////////////////////////////////////////////////////////////////////////// +// // +// GUI for the TMemStat // +// used for the memomry checker // +// Example usage: // +/* + aliroot + TMemStatViewer::ShowGUI("memstat.root") +*/ +// - Resize windows - (BUG to BE FIXED -> ROOT bug) // +// // +////////////////////////////////////////////////////////////////////////////// + +// STD +#include <functional> +#include <stdexcept> +#include <algorithm> +// ROOT +#include "TGTextView.h" +#include "TGLabel.h" +#include "TGTab.h" +#include "TGButton.h" +#include "TGNumberEntry.h" +#include "TGSplitter.h" +#include "TGButtonGroup.h" +#include "TGComboBox.h" +#include "TObjArray.h" +// Memstat +#include "TMemStat.h" +#include "TMemViewerGUI.h" +#include "TMemStatResource.h" +#include "TMemStatDrawDlg.h" + +ClassImp(TMemViewerGUI) + +using namespace std; + + +//______________________________________________________________________________ +struct SStringToListBox : public binary_function<string, TGComboBox*, bool> { + bool operator()(string str, TGComboBox* box) const { + if (!box) + return false; + + box->AddEntry(str.c_str(), box->GetNumberOfEntries()); + return true; + } +}; + +//______________________________________________________________________________ +struct SFillListBox : public binary_function<TObject*, TGComboBox*, bool> { + bool operator()(TObject *aObj, TGComboBox* box) const { + if (!aObj || !box) + return false; //TODO: need an assert "SFillListBox: parametr is a NULL pointer" + + if ((aObj->IsA() == TObjString::Class())) { + TObjString *str(dynamic_cast<TObjString*>(aObj)); + if (!str) + return false; // TODO: need an assert "SFillListBox: Container's element is not a TObjString object." + + SStringToListBox()(str->String().Data(), box); + } + + return true; + } +}; + +//______________________________________________________________________________ +TMemViewerGUI::TMemViewerGUI(const TGWindow *p, UInt_t w, UInt_t h, Option_t* option): + TGCompositeFrame(p, w, h), + fViewer(NULL), + fText(NULL), + fNmbStackDeep(NULL), + fNmbSortDeep(NULL) +{ + // TMemViewerGUI constructor; fileName specifies the ROOT tree used for drawing + + SetCleanup(kDeepCleanup); + + // ************************* content of this MainFrame ************************* + // top level container with horizontal layout + // container for all GUI elements, vertical divided + TGCompositeFrame *ContMain = new TGCompositeFrame(this, w, h, kVerticalFrame | kFixedWidth | kFixedHeight); + AddFrame(ContMain, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY)); + + // container for all GUI elements, horizontal divided + TGCompositeFrame *ContLCR = new TGCompositeFrame(ContMain, w, h, kHorizontalFrame | kFixedWidth | kFixedHeight); + ContMain->AddFrame(ContLCR, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY)); + + // ************************* content of ContLCR ************************* + // container for GUI elements on left side + TGCompositeFrame *ContLeft = new TGCompositeFrame(ContLCR, 160, 200, kVerticalFrame | kFixedWidth | kFitHeight); + ContLCR->AddFrame(ContLeft, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY, 5, 3, 3, 3)); + + // left vertical splitter + TGVSplitter *splitLeft = new TGVSplitter(ContLCR); + splitLeft->SetFrame(ContLeft, kTRUE); + ContLCR->AddFrame(splitLeft, new TGLayoutHints(kLHintsLeft | kLHintsExpandY)); + + // container for GUI elements at the center + TGCompositeFrame *ContCenter = new TGCompositeFrame(ContLCR, 150, 200, kVerticalFrame | kFixedWidth | kFitHeight); + ContLCR->AddFrame(ContCenter, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY)); + + fText = new TGTextView(ContCenter); + ContCenter->AddFrame(fText, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY)); + + // Display everything + Initialize(option); + + MakeStampList(ContLeft); + MakeSelection(ContLeft); + MakeContSortStat(ContLeft); // Make content for Sort Statistic + MakeContSortStamp(ContLeft); // make constent for sort Stamps + MakeContDeep(ContLeft); // make constent for sort Stamps + MakeDrawButton(ContLeft); + + MapSubwindows(); + Resize(GetDefaultSize()); + MapWindow(); + + // Default View + fViewer->fSortStat = TMemStat::kTotalAllocCount; + fViewer->fSortStamp = TMemStat::kCurrent; + MakePrint(); +} + +//______________________________________________________________________________ +TMemViewerGUI::~TMemViewerGUI() +{ + Cleanup(); + if (fViewer) + fViewer->Delete(); +} + +//______________________________________________________________________________ +void TMemViewerGUI::Initialize(Option_t* option) +{ + // initializes the GUI with default settings and opens tree for drawing + + delete fViewer; + fViewer = new TMemStat(option); + fViewer->Report(); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakeContSortStat(TGCompositeFrame *frame) +{ + // make windows for Sorting *STAT* selection + + // sorting statistic option + TGVButtonGroup *SortStatGroup = new TGVButtonGroup(frame, "Statistic type"); + frame->AddFrame(SortStatGroup, new TGLayoutHints(kLHintsExpandX)); + new TGRadioButton(SortStatGroup, "Total Alloc Count", rbtnTotalAllocCount); + new TGRadioButton(SortStatGroup, "Total Alloc Size", rbtnTotalAllocSize); + new TGRadioButton(SortStatGroup, "Alloc Count", rbtnAllocCount); + new TGRadioButton(SortStatGroup, "Alloc Size", rbtnAllocSize); + SortStatGroup->SetButton(rbtnTotalAllocCount); + SortStatGroup->Connect("Pressed(Int_t)", "TMemViewerGUI", this, "HandleButtonsSortStat(Int_t)"); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakeContSortStamp(TGCompositeFrame *frame) +{ + // make windows for Sorting *STAMP* selection + + // sorting stamp option + TGVButtonGroup *SortStampGroup = new TGVButtonGroup(frame, "Sorting stamp"); + frame->AddFrame(SortStampGroup, new TGLayoutHints(kLHintsExpandX)); + new TGRadioButton(SortStampGroup, "Current", rbtnCurrent); + new TGRadioButton(SortStampGroup, "Max Size", rbtnMaxSize); + new TGRadioButton(SortStampGroup, "Max Count", rbtnMaxCount); + SortStampGroup->SetButton(rbtnCurrent); + SortStampGroup->Connect("Pressed(Int_t)", "TMemViewerGUI", this, "HandleButtonsSortStamp(Int_t)"); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakeStampList(TGCompositeFrame *frame) +{ + // make STAMPs list box + + if (!fViewer) + return; + + const TObjArray *StampList = fViewer->GetStampList(); + if (!StampList) + return; + + TGHorizontalFrame *horz = new TGHorizontalFrame(frame); + frame->AddFrame(horz, new TGLayoutHints(kLHintsExpandX, 2, 2, 10, 2)); + // text description + TGLabel *lblName = new TGLabel(horz, "Stamp name:"); + horz->AddFrame(lblName, + new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 2, 2, 2, 2)); + + // a list box of stamps + TGComboBox *StampListBox = new TGComboBox(horz, lstStamps); + StampListBox->Resize(100, 20); + horz->AddFrame(StampListBox, new TGLayoutHints(kLHintsExpandX)); + StampListBox->Connect("Selected(const char*)", "TMemViewerGUI", this, "HandleStampSelect(const char*)"); + + // filling Combo box of stamps + TIter iter(StampList); + for_each(iter.Begin(), TIter::End(), + bind2nd(SFillListBox(), StampListBox)); + + const Int_t count(StampListBox->GetNumberOfEntries()); + if (count <= 0) + return; + // Selecting the last stamp + StampListBox->Select(count - 1); + + TObjString *str(dynamic_cast<TObjString*>(StampList->At(StampListBox->GetSelected()))); + if (!str) + return; + + fViewer->SetCurrentStamp(*str); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleStampSelect(const char* value) +{ + fViewer->SetCurrentStamp(value); + MakePrint(); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakeContDeep(TGCompositeFrame *frame) +{ + // create and layout "Deep" controls + + TGGroupFrame *ContDeep = new TGGroupFrame(frame, "Deepnes"); + ContDeep->SetLayoutManager(new TGMatrixLayout(ContDeep, 0, 2, 5)); + frame->AddFrame(ContDeep, new TGLayoutHints(kLHintsExpandX)); + + // ------ Stack Deep + // text description + TGLabel *lblStackDeep = new TGLabel(ContDeep, "Stack Deep:"); + ContDeep->AddFrame(lblStackDeep, 0); + // number entry box for specifying the stack deepness + fNmbStackDeep = new TGNumberEntry(ContDeep, fViewer->fStackDeep, 1, -1, TGNumberFormat::kNESInteger, + TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 1, 50); + ContDeep->AddFrame(fNmbStackDeep, 0); + fNmbStackDeep->Connect("ValueSet(Long_t)", "TMemViewerGUI", this, "HandleDeep(Long_t)"); + fNmbStackDeep->Resize(60, 20); + + // ------ Sort Deep + // text description + TGLabel *LabSortDeep = new TGLabel(ContDeep, "Sort Deep:"); + ContDeep->AddFrame(LabSortDeep, 0); + // number entry box for specifying the number of stamps + fNmbSortDeep = new TGNumberEntry(ContDeep, fViewer->fStackDeep, 1, -1, TGNumberFormat::kNESInteger, + TGNumberFormat::kNEANonNegative, TGNumberFormat::kNELLimitMinMax, 1, 50); + ContDeep->AddFrame(fNmbSortDeep, 0); + fNmbSortDeep->Connect("ValueSet(Long_t)", "TMemViewerGUI", this, "HandleDeep(Long_t)"); + fNmbSortDeep->Resize(60, 20); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakeDrawButton(TGCompositeFrame *frame) +{ + // Creats a "Draw TMemStat" button + + // TODO: Move this to Menu. Make it a main menu item instead of a button + + TGHorizontalFrame *horz = new TGHorizontalFrame(frame); + frame->AddFrame(horz, new TGLayoutHints(kLHintsExpandX)); + // text description + TGTextButton *btnDraw = new TGTextButton(horz); + btnDraw->SetText("&Draw TMemStat"); + horz->AddFrame(btnDraw, + new TGLayoutHints(kLHintsLeft | kLHintsCenterY, 2, 2, 10, 10)); + btnDraw->Connect("Clicked()", "TMemViewerGUI", this, "HandleDrawMemStat()"); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleDrawMemStat() +{ + new TMemStatDrawDlg(gClient->GetRoot(), this, fViewer); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleButtonsSortStat(Int_t id) +{ + // handles mutual radio button exclusions - set sort stat type + + HandleRButtons(id, rbtnTotalAllocCount, &fViewer->fSortStat); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleButtonsSortStamp(Int_t id) +{ + // handles mutual radio button exclusions - set sort stat type + + HandleRButtons(id, rbtnCurrent, &fViewer->fSortStamp); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleDeep(Long_t /*id*/) +{ + // handles stack deep + + fViewer->fStackDeep = fNmbStackDeep->GetIntNumber(); + fViewer->fSortDeep = fNmbSortDeep->GetIntNumber(); + MakePrint(); +} + +//______________________________________________________________________________ +void TMemViewerGUI::ShowGUI() +{ + // initialize and show GUI for presentation + + TGMainFrame* frmMain = new TGMainFrame(gClient->GetRoot(), 800, 600); + frmMain->SetWindowName("TMemStat analysis console"); + frmMain->SetCleanup(kDeepCleanup); + + TMemViewerGUI* calibViewer1 = new TMemViewerGUI(frmMain, 800, 600, "read"); + frmMain->AddFrame(calibViewer1, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY)); + + frmMain->MapSubwindows(); + frmMain->Resize(); + frmMain->MapWindow(); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakePrint() +{ + // make report and load it to the view + fViewer->MakeReport( fCurLib.c_str(), fCurFunc.c_str(), 0, "/tmp/memstatprint.txt"); + fText->LoadFile("/tmp/memstatprint.txt"); +} + +//______________________________________________________________________________ +void TMemViewerGUI::MakeSelection(TGCompositeFrame *frame) +{ + if (!fViewer) + return; + + TGGroupFrame *grp = new TGGroupFrame(frame, "Selections"); + frame->AddFrame(grp, new TGLayoutHints(kLHintsExpandX)); + + // ----- Function + // text description + TGLabel *lblFun = new TGLabel(grp, "Function"); + grp->AddFrame(lblFun, new TGLayoutHints(kLHintsExpandX )); + // a list box of stamps + TGComboBox *lboxFunctions = new TGComboBox(grp); + lboxFunctions->Resize(100, 20); + grp->AddFrame(lboxFunctions, new TGLayoutHints(kLHintsExpandX )); + lboxFunctions->Connect("Selected(const char*)", "TMemViewerGUI", this, "HandleFuncSelect(const char*)"); + + // Add default selection - select all + lboxFunctions->AddEntry("*", 0); + // Fill values for Functions + TMemStat::Selection_t container; + fViewer->GetFillSelection( &container, TMemStat::kFunction ); + for_each(container.begin(), container.end(), + bind2nd(SStringToListBox(), lboxFunctions)); + lboxFunctions->Select(0); + + // ----- Library + // text description + TGLabel *lblLib = new TGLabel(grp, "Libraries"); + grp->AddFrame(lblLib, new TGLayoutHints(kLHintsExpandX)); + // a list box of stamps + TGComboBox *lboxLibraries = new TGComboBox(grp); + lboxLibraries->Resize(100, 20); + grp->AddFrame(lboxLibraries, new TGLayoutHints(kLHintsExpandX )); + lboxLibraries->Connect("Selected(const char*)", "TMemViewerGUI", this, "HandleLibSelect(const char*)"); + + // Add default selection - select all + lboxLibraries->AddEntry("*", 0); + // Fill values for Functions + container.clear(); + fViewer->GetFillSelection( &container, TMemStat::kLibrary ); + for_each(container.begin(), container.end(), + bind2nd(SStringToListBox(), lboxLibraries)); + lboxLibraries->Select(0); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleFuncSelect(const char* _val) +{ + fCurFunc = _val; + // if _val == "*" then we don't sort + if ( fCurFunc.find("*") != string::npos ) + fCurFunc.clear(); + + MakePrint(); +} + +//______________________________________________________________________________ +void TMemViewerGUI::HandleLibSelect(const char* _val) +{ + fCurLib = _val; + // if _val == "*" then we don't sort + if ( fCurLib.find("*") != string::npos ) + fCurLib.clear(); + + MakePrint(); +} -- GitLab