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