ROOT  6.07/01
Reference Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
memstatExample.C
Go to the documentation of this file.
1 // script post-processing the file generated by TMemStat (default memstat.root)
2 //
3 // To use the class TMemStat, add the following statement at the beginning
4 // of your script or program
5 // TMemStat mm("gnubuiltin");
6 // or in an interactive session do something like:
7 // root > TMemStat mm("gnubuiltin");
8 // root > .x somescript.C
9 // root > .q
10 // TMemStat records all the calls to malloc and free and write a TTree
11 // with the position where the memory is allocated/freed , as well as
12 // the number of bytes.
13 //
14 // This script creates 2 canvases.
15 // -In canvas1 it displays a dynamic histogram showing for pages (10 kbytes by default)
16 // the percentage of the page used.
17 // A summary pave shows the total memory still in use when the TMemStat object
18 // goes out of scope and the average occupancy of the pages.
19 // The average occupancy gives a good indication of the memory fragmentation.
20 //
21 // -In canvas2 it displays the histogram of memory leaks in decreasing order.
22 // when moving the mouse on this canvas, a tooltip shows the backtrace for the leak
23 // in the bin below the mouse.
24 //
25 // The script can be executed simply as
26 // root > .x memstat.C (or via ACLIC .x memstat.C+ )
27 // or specifying arguments
28 // root > .x memstat.C+(0.01,"mydir/mymemstat.root");
29 //
30 // The first argument to the script is the percentage of the time of the original job
31 // that produced the file after which the display is updated. By default update=0.01,
32 // ie 100 time intervals will be shown.
33 // The second argument is the imput file name (result of TMemStat).
34 // If this argument is omitted, the script will take the most recent file
35 // generated by TMemStat.
36 //
37 //Author: Rene Brun 7 July 2010
38 
39 #include "TMath.h"
40 #include "TFile.h"
41 #include "TTree.h"
42 #include "TCanvas.h"
43 #include "TStyle.h"
44 #include "TH1.h"
45 #include "TPaveText.h"
46 #include "TPaveLabel.h"
47 #include "TSystem.h"
48 #include "TGClient.h"
49 #include "TGToolTip.h"
50 #include "TRootCanvas.h"
51 
57 TGToolTip *gTip = 0;
58 TObjArray *btidlist=0;
59 Double_t *V1, *V2, *V3, *V4;
60 
61 void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected);
62 
63 void memstatExample(double update=0.01, const char* fname="*") {
64  // Open the memstat data file, then call TTree::Draw to precompute
65  // the arrays of positions and nbytes per entry.
66  // update is the time interval in the data file in seconds after which
67  // the display is updated. For example is the job producing the memstat.root file
68  // took 100s to execute, an update of 0.1s will generate 1000 time views of
69  // the memory use.
70  // if fname=="*" (default), the most recent file memstat*.root will be taken.
71 
72  TString s;
73  if (!fname || strlen(fname) <5 || strstr(fname,"*")) {
74  //take the most recent file memstat*.root
75  s = gSystem->GetFromPipe("ls -lrt memstat*.root");
76  Int_t ns = s.Length();
77  fname = strstr(s.Data()+ns-25,"memstat");
78  }
79  printf("Analyzing file: %s\n",fname);
80  f = TFile::Open(fname);
81  if (!f) {
82  printf("Cannot open file %s\n",fname);
83  return;
84  }
85  T = (TTree*)f->Get("T");
86  if (!T) {
87  printf("cannot find the TMemStat TTree named T in file %s\n",fname);
88  return;
89  }
90  if (update <= 0) {
91  printf("Illegal update value %g, changed to 0.01\n",update);
92  update = 0.01;
93  }
94  if (update < 0.001) printf("Warning update parameter is very small, processing may be slow\n");
95 
96 
98  T->SetEstimate(nentries+10);
99  Long64_t nsel = T->Draw("pos:nbytes:time:btid","","goff");
100 
101  //now we compute the best binning for the histogram
102  Int_t nbytes;
103  Double_t pos;
104  V1 = T->GetV1();
105  V2 = T->GetV2();
106  V3 = T->GetV3();
107  V4 = T->GetV4();
108  Long64_t imean = (Long64_t)TMath::Mean(nsel,V1);
109  Long64_t irms = (Long64_t)TMath::RMS(nsel,V1);
110  //Long64_t bw = 10000;
111  Long64_t bw = 1000;
112  imean = imean - imean%bw;
113  irms = irms -irms%bw;
114  Int_t nbins = Int_t(4*irms/bw);
115  Long64_t ivmin = imean -bw*nbins/2;
116  Long64_t ivmax = ivmin+bw*nbins;
117  if (ivmax > 2000000000 && ivmin <2000000000) {
118  //the data set has been likely generated on a 32 bits machine
119  //we are mostly interested by the small allocations, so we select
120  //only values below 2 GBytes
121  printf("memory locations above 2GBytes will be ignored\n");
122  nsel = T->Draw("pos:nbytes:time:btid","pos <2e9","goff");
123  V1 = T->GetV1();
124  V2 = T->GetV2();
125  V3 = T->GetV3();
126  V4 = T->GetV4();
127  imean = (Long64_t)TMath::Mean(nsel,V1);
128  irms = (Long64_t)TMath::RMS(nsel,V1);
129  bw = 10000;
130  imean = imean - imean%bw;
131  irms = irms -irms%bw;
132  nbins = Int_t(4*irms/bw);
133  ivmin = imean -bw*nbins/2;
134  ivmax = ivmin+bw*nbins;
135  }
136  update *= 0.0001*V3[nsel-1]; //convert time per cent in seconds
137  Long64_t nvm = Long64_t(ivmax-ivmin+1);
138  Long64_t *nbold = new Long64_t[nvm];
139  Int_t *ientry = new Int_t[nvm];
140  memset(nbold,0,nvm*8);
141  Double_t dv = (ivmax-ivmin)/nbins;
142  h = new TH1D("h",Form("%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax);
143  TAxis *axis = h->GetXaxis();
144  gStyle->SetOptStat("ie");
145  h->SetFillColor(kRed);
146  h->SetMinimum(0);
147  h->SetMaximum(100);
148  halloc = new TH1D("halloc",Form("%s;pos;number of mallocs",fname),nbins,ivmin,ivmax);
149  hfree = new TH1D("hfree", Form("%s;pos;number of frees",fname),nbins,ivmin,ivmax);
150  //open a canvas and draw the empty histogram
151  TCanvas *c1 = new TCanvas("c1","c1",1200,600);
152  c1->SetFrameFillColor(kYellow-3);
153  c1->SetGridx();
154  c1->SetGridy();
155  h->Draw();
156  //create a TPaveText to show the summary results
157  TPaveText *pvt = new TPaveText(.5,.9,.75,.99,"brNDC");
158  pvt->Draw();
159  //create a TPaveLabel to show the time
160  TPaveLabel *ptime = new TPaveLabel(.905,.7,.995,.76,"time","brNDC");
161  ptime->SetFillColor(kYellow-3);
162  ptime->Draw();
163  //draw producer identifier
164  TNamed *named = (TNamed*)T->GetUserInfo()->FindObject("SysInfo");
165  TText tmachine;
166  tmachine.SetTextSize(0.02);
167  tmachine.SetNDC();
168  if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
169 
170  //start loop on selected rows
171  Int_t bin,nb=0,j;
172  Long64_t ipos;
173  Double_t dbin,rest,time;
174  Double_t updateLast = 0;
175  Int_t nleaks = 0;
176  Int_t i;
177  for (i=0;i<nsel;i++) {
178  pos = V1[i];
179  ipos = (Long64_t)(pos-ivmin);
180  nbytes = (Int_t)V2[i];
181  time = 0.0001*V3[i];
182  bin = axis->FindBin(pos);
183  if (bin<1 || bin>nbins) continue;
184  dbin = axis->GetBinUpEdge(bin)-pos;
185  if (nbytes > 0) {
186  halloc->Fill(pos);
187  if (dbin > nbytes) dbin = nbytes;
188  //fill bytes in the first page
189  h->AddBinContent(bin,100*dbin/dv);
190  //fill bytes in full following pages
191  nb = Int_t((nbytes-dbin)/dv);
192  if (bin+nb >nbins) nb = nbins-bin;
193  for (j=1;j<=nb;j++) h->AddBinContent(bin+j,100);
194  //fill the bytes remaining in last page
195  rest = nbytes-nb*dv-dbin;
196  if (rest > 0) h->AddBinContent(bin+nb+1,100*rest/dv);
197  //we save nbytes at pos. This info will be used when we free this slot
198  if (nbold[ipos] > 0) printf("reallocating %d bytes (was %lld) at %lld, entry=%d\n",nbytes,nbold[ipos],ipos,i);
199  if (nbold[ipos] == 0) {
200  nleaks++;
201  //save the Tree entry number where we made this allocation
202  ientry[ipos] = i;
203  }
204  nbold[ipos] = nbytes;
205  } else {
206  hfree->Fill(pos);
207  nbytes = nbold[ipos];
208  if (bin+nb >nbins) nb = nbins-bin;
209  nbold[ipos] = 0; nleaks--;
210  if (nbytes <= 0) continue;
211  //fill bytes free in the first page
212  if (dbin > nbytes) dbin = nbytes;
213  h->AddBinContent(bin,-100*dbin/dv);
214  //fill bytes free in full following pages
215  nb = Int_t((nbytes-dbin)/dv);
216  if (bin+nb >nbins) nb = nbins-bin;
217  for (j=1;j<=nb;j++) h->AddBinContent(bin+j,-100);
218  //fill the bytes free in in last page
219  rest = nbytes-nb*dv-dbin;
220  if (rest > 0) h->AddBinContent(bin+nb+1,-100*rest/dv);
221 
222  }
223  if (time -updateLast > update) {
224  //update canvas at regular intervals
225  updateLast = time;
226  h->SetEntries(i);
227  c1->Modified();
228  pvt->GetListOfLines()->Delete();
229  Double_t mbytes = 0;
230  Int_t nonEmpty = 0;
231  Double_t w;
232  for (Int_t k=1;k<nbins;k++) {
233  w = h->GetBinContent(k);
234  if (w > 0) {
235  nonEmpty++;
236  mbytes += 0.01*w*dv;
237  }
238  }
239  Double_t occupancy = mbytes/(nonEmpty*0.01*dv);
240  pvt->AddText(Form("memory used = %g Mbytes",mbytes*1e-6));
241  pvt->AddText(Form("page occupancy = %f per cent",occupancy));
242  pvt->AddText("(for non empty pages only)");
243  ptime->SetLabel(Form("%g sec",time));
244 
245  c1->Update();
247  }
248  }
249  h->SetEntries(nsel);
250  Int_t nlmax = nleaks;
251  nleaks += 1000;
252  Int_t *lindex = new Int_t[nleaks];
253  Int_t *entry = new Int_t[nleaks];
254  Int_t *ileaks = new Int_t[nleaks];
255 
256  nleaks =0;
257  for (Int_t ii=0;ii<nvm;ii++) {
258  if (nbold[ii] > 0) {
259  ileaks[nleaks] = (Int_t)nbold[ii];
260  entry[nleaks] = ientry[ii];
261  nleaks++;
262  if (nleaks > nlmax) break;
263  }
264  }
265 
266  TMath::Sort(nleaks,ileaks,lindex);
267  hentry = new TH1I("hentry","leak entry index",nleaks,0,nleaks);
268  hleaks = new TH1I("hleaks","leaks;leak number;nbytes in leak",nleaks,0,nleaks);
269  for (Int_t k=0;k<nleaks;k++) {
270  Int_t kk = lindex[k];
271  i = entry[kk];
272  hentry->SetBinContent(k+1,i);
273  hleaks->SetBinContent(k+1,ileaks[kk]);
274  }
275  hentry->SetEntries(nleaks);
276  hleaks->SetEntries(nleaks);
277 
278  //open a second canvas and draw the histogram with leaks in decreasing order
279  TCanvas *c2 = new TCanvas("c2","c2",1200,600);
280  c2->SetFrameFillColor(kCyan-6);
281  c2->SetGridx();
282  c2->SetGridy();
283  c2->SetLogy();
284  hleaks->SetFillColor(kRed-3);
285  if (nleaks > 1000) hleaks->GetXaxis()->SetRange(1,1000);
286  hleaks->Draw();
287  //draw producer identifier
288  if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
289 
290  //construct the tooltip
291  TRootCanvas *rc = (TRootCanvas *)c2->GetCanvasImp();
292  TGMainFrame *frm = dynamic_cast<TGMainFrame *>(rc);
293  // create the tooltip with a timeout of 250 ms
294  if (!gTip) gTip = new TGToolTip(gClient->GetDefaultRoot(), frm, "", 250);
295  c2->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
296  0, 0, "EventInfo(Int_t, Int_t, Int_t, TObject*)");
297 
298 }
299 
300 //______________________________________________________________________
301 void EventInfo(Int_t event, Int_t px, Int_t , TObject *selected)
302 {
303  //draw the tooltip showing the backtrace for the bin at px
304  if (!gTip) return;
305  gTip->Hide();
306  if (event == kMouseLeave)
307  return;
308  Double_t xpx = gPad->AbsPixeltoX(px);
309  Int_t bin = hleaks->GetXaxis()->FindBin(xpx);
310  if (bin <=0 || bin > hleaks->GetXaxis()->GetNbins()) return;
311  Int_t nbytes = (Int_t)hleaks->GetBinContent(bin);
312  Int_t entry = (Int_t)hentry->GetBinContent(bin);
313  Int_t btid = (Int_t)V4[entry];
314  Double_t time = 0.0001*V3[entry];
315  TH1I *hbtids = (TH1I*)T->GetUserInfo()->FindObject("btids");
316  if (!hbtids) return;
317  if (!btidlist) btidlist = (TObjArray*)T->GetUserInfo()->FindObject("FAddrsList");
318  if (!btidlist) btidlist = (TObjArray*)f->Get("FAddrsList"); //old memstat files
319  if (!btidlist) return;
320  Int_t nbt = (Int_t)hbtids->GetBinContent(btid-1);
321  TString ttip;
322  for (Int_t i=0;i<nbt;i++) {
323  Int_t j = (Int_t)hbtids->GetBinContent(btid+i);
324  TNamed *nm = (TNamed*)btidlist->At(j);
325  if (nm==0) break;
326  char *title = (char*)nm->GetTitle();
327  Int_t nch = strlen(title);
328  if (nch < 20) continue;
329  if (nch > 100) title[100] =0;
330  const char *bar = strstr(title,"| ");
331  if (!bar) continue;
332  if (strstr(bar,"operator new")) continue;
333  if (strstr(bar,"libMemStat")) continue;
334  if (strstr(bar,"G__Exception")) continue;
335  ttip += TString::Format("%2d %s\n",i,bar+1);
336  }
337 
338  if (selected) {
339  TString form1 = TString::Format(" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time);
340  gTip->SetText(TString::Format("%s%s",form1.Data(),ttip.Data() ));
341  gTip->SetPosition(px+15, 100);
342  gTip->Reset();
343  }
344 }
TControlBar * bar
Definition: demos.C:15
virtual Double_t * GetV3()
Definition: TTree.h:458
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:52
virtual void SetGridx(Int_t value=1)
Definition: TPad.h:327
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3159
An array of TObjects.
Definition: TObjArray.h:39
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:420
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:405
virtual void Draw(Option_t *option="")
Draw this pavetext with its current attributes.
Definition: TPaveText.cxx:211
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition: TH1.cxx:4629
long long Long64_t
Definition: RtypesCore.h:69
virtual void SetMaximum(Double_t maximum=-1111)
Definition: TH1.h:394
Ssiz_t Length() const
Definition: TString.h:390
virtual Double_t * GetV4()
Definition: TTree.h:460
Double_t * V1
TCanvas * c1
Definition: legend1.C:2
Definition: Rtypes.h:61
void Reset()
Reset tool tip popup delay timer.
Definition: TGToolTip.cxx:259
R__EXTERN TStyle * gStyle
Definition: TStyle.h:423
void SetText(const char *new_text)
Set new tool tip text.
Definition: TGToolTip.cxx:386
virtual TString GetFromPipe(const char *command)
Execute command and return output in TString.
Definition: TSystem.cxx:684
TH1D * halloc
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:45
virtual TText * AddText(Double_t x1, Double_t y1, const char *label)
Add a new Text line to this pavetext at given coordinates.
Definition: TPaveText.cxx:160
virtual TObject * Get(const char *namecycle)
Return pointer to object identified by namecycle.
virtual void SetMinimum(Double_t minimum=-1111)
Definition: TH1.h:395
Basic string class.
Definition: TString.h:137
#define gClient
Definition: TGClient.h:174
int Int_t
Definition: RtypesCore.h:41
virtual TList * GetListOfLines() const
Definition: TPaveText.h:63
virtual TObject * FindObject(const char *name) const
Find an object in this list using its name.
Definition: TList.cxx:497
void Hide()
Hide tool tip window.
Definition: TGToolTip.cxx:246
int nbins[3]
Definition: Rtypes.h:61
Float_t py
Definition: hprod.C:33
TFile * f
TH1D * hfree
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=1, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3851
TH1I * hleaks
TTree * T
const char * Data() const
Definition: TString.h:349
Double_t RMS(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:916
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString...
Definition: TString.cxx:2321
The TNamed class is the base class for all named ROOT classes.
Definition: TNamed.h:33
virtual void AddBinContent(Int_t bin)
Increment bin content by 1.
Definition: TH1.h:625
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Definition: TMath.h:1002
Base class for several text objects.
Definition: TText.h:42
virtual void SetNDC(Bool_t isNDC=kTRUE)
Set NDC mode on if isNDC = kTRUE, off otherwise.
Definition: TText.cxx:809
void SetPosition(Int_t x, Int_t y)
Set popup position within specified frame (as specified in the ctor).
Definition: TGToolTip.cxx:405
virtual TList * GetUserInfo()
Return a pointer to the list containing user objects associated to this tree.
Definition: TTree.cxx:5673
virtual void SetLabel(const char *label)
Definition: TPaveLabel.h:53
A Pave (see TPave) with a text centered in the Pave.
Definition: TPaveLabel.h:32
Bool_t Connect(const char *signal, const char *receiver_class, void *receiver, const char *slot)
Non-static method is used to connect from the signal of this object to the receiver slot...
Definition: TQObject.cxx:1135
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis from bin first to last.
Definition: TAxis.cxx:831
Double_t * V3
virtual void SetEstimate(Long64_t nentries=1000000)
Set number of entries to estimate variable limits.
Definition: TTree.cxx:8205
Class to manage histogram axis.
Definition: TAxis.h:36
R__EXTERN TSystem * gSystem
Definition: TSystem.h:545
virtual void Draw(Option_t *option="")
Draw this histogram with options.
Definition: TH1.cxx:2878
tuple form1
Definition: fillrandom.py:24
TPaveLabel title(3, 27.1, 15, 28.7,"ROOT Environment and Tools")
virtual void SetFillColor(Color_t fcolor)
Definition: TAttFill.h:50
Int_t GetNbins() const
Definition: TAxis.h:125
virtual Double_t * GetV2()
Definition: TTree.h:456
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition: TAxis.cxx:499
1-D histogram with a int per channel (see TH1 documentation)}
Definition: TH1.h:529
virtual void SetBinContent(Int_t bin, Double_t content)
Set bin content see convention for numbering bins in TH1::GetBin In case the bin number is greater th...
Definition: TH1.cxx:8543
Double_t Mean(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:824
static void update(gsl_integration_workspace *workspace, double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
char * Form(const char *fmt,...)
TH1D * h
tuple w
Definition: qtexample.py:51
1-D histogram with a double per channel (see TH1 documentation)}
Definition: TH1.h:613
Long64_t entry
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition: TAxis.cxx:264
TH1I * hentry
The Canvas class.
Definition: TCanvas.h:48
TCanvasImp * GetCanvasImp() const
Get canvas implementation pointer if any.
Definition: TCanvas.h:181
return c2
Definition: legend2.C:14
A Pave (see TPave) with text, lines or/and boxes inside.
Definition: TPaveText.h:35
virtual void Draw(Option_t *option="")
Draw this pavelabel with its current attributes.
Definition: TPaveLabel.cxx:77
double Double_t
Definition: RtypesCore.h:55
virtual void SetGridy(Int_t value=1)
Definition: TPad.h:328
ClassImp(TMCParticle) void TMCParticle printf(": p=(%7.3f,%7.3f,%9.3f) ;", fPx, fPy, fPz)
virtual void Draw(Option_t *opt)
Default Draw method for all objects.
Definition: TTree.h:360
int nentries
Definition: THbookFile.cxx:89
Definition: Rtypes.h:61
Mother of all ROOT objects.
Definition: TObject.h:58
void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected)
Float_t px
Definition: hprod.C:33
Bool_t axis
Definition: geodemo.C:37
void memstatExample(double update=0.01, const char *fname="*")
void SetOptStat(Int_t stat=1)
The type of information printed in the histogram statistics box can be selected via the parameter mod...
Definition: TStyle.cxx:1252
virtual TText * DrawText(Double_t x, Double_t y, const char *text)
Draw this text with new coordinates.
Definition: TText.cxx:171
#define gPad
Definition: TVirtualPad.h:288
virtual void SetEntries(Double_t n)
Definition: TH1.h:382
virtual Long64_t GetEntries() const
Definition: TTree.h:386
A TTree object has a header with a name and a title.
Definition: TTree.h:98
void SetFrameFillColor(Color_t color=1)
Definition: TAttPad.h:83
virtual void SetTextSize(Float_t tsize=1)
Definition: TAttText.h:60
TObject * At(Int_t idx) const
Definition: TObjArray.h:167
virtual void Update()
Update canvas pad buffers.
Definition: TCanvas.cxx:2179
Double_t * V4
virtual Double_t * GetV1()
Definition: TTree.h:454
void Modified(Bool_t flag=1)
Definition: TPad.h:407
TAxis * GetXaxis()
Definition: TH1.h:319
Double_t * V2
virtual void SetLogy(Int_t value=1)
Set Lin/Log scale for Y.
Definition: TPad.cxx:5314
int ii
Definition: hprod.C:34