Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
memstatExample.C
Go to the documentation of this file.
1/// \file
2/// \ingroup tutorial_heritage
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
74TFile *f;
75TTree *T;
76TH1D *h;
77TH1D *halloc, *hfree;
78TH1I *hleaks, *hentry;
79TGToolTip *gTip = 0;
80TObjArray *btidlist=0;
81Double_t *V1, *V2, *V3, *V4;
82
83void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected);
84
85void 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
119 Long64_t nentries = T->GetEntries();
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//______________________________________________________________________
323void 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}
@ kMouseLeave
Definition Buttons.h:23
#define f(i)
Definition RSha256.hxx:104
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
static void update(gsl_integration_workspace *workspace, double a1, double b1, double area1, double error1, double a2, double b2, double area2, double error2)
int Int_t
Definition RtypesCore.h:45
double Double_t
Definition RtypesCore.h:59
long long Long64_t
Definition RtypesCore.h:73
@ kRed
Definition Rtypes.h:66
@ kCyan
Definition Rtypes.h:66
@ kYellow
Definition Rtypes.h:66
#define gClient
Definition TGClient.h:166
int nentries
char * Form(const char *fmt,...)
R__EXTERN TStyle * gStyle
Definition TStyle.h:412
R__EXTERN TSystem * gSystem
Definition TSystem.h:559
#define gPad
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
Definition TAttFill.h:37
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
Definition TAttText.h:46
Class to manage histogram axis.
Definition TAxis.h:30
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition TAxis.cxx:293
Int_t GetNbins() const
Definition TAxis.h:121
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis using bin numbers.
Definition TAxis.cxx:920
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition TAxis.cxx:528
The Canvas class.
Definition TCanvas.h:23
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition TFile.h:54
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseCompiledDefault, Int_t netopt=0)
Create / open a file.
Definition TFile.cxx:3997
void Hide()
Hide tool tip window.
void SetPosition(Int_t x, Int_t y)
Set popup position within specified frame (as specified in the ctor).
void SetText(const char *new_text)
Set new tool tip text.
void Reset()
Reset tool tip popup delay timer.
1-D histogram with a double per channel (see TH1 documentation)}
Definition TH1.h:618
1-D histogram with an int per channel (see TH1 documentation)}
Definition TH1.h:534
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition TH1.h:320
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition TH1.cxx:3350
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:9062
virtual void Draw(Option_t *option="")
Draw this histogram with options.
Definition TH1.cxx:3073
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition TH1.cxx:4993
virtual void SetEntries(Double_t n)
Definition TH1.h:385
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition TList.cxx:470
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
virtual const char * GetTitle() const
Returns title of object.
Definition TNamed.h:48
An array of TObjects.
Definition TObjArray.h:37
TObject * At(Int_t idx) const
Definition TObjArray.h:166
Mother of all ROOT objects.
Definition TObject.h:37
A Pave (see TPave) with a text centered in the Pave.
Definition TPaveLabel.h:20
virtual void Draw(Option_t *option="")
Draw this pavelabel with its current attributes.
virtual void SetLabel(const char *label)
Definition TPaveLabel.h:41
A Pave (see TPave) with text, lines or/and boxes inside.
Definition TPaveText.h:21
virtual TText * AddText(Double_t x1, Double_t y1, const char *label)
Add a new Text line to this pavetext at given coordinates.
virtual void Draw(Option_t *option="")
Draw this pavetext with its current attributes.
virtual TList * GetListOfLines() const
Definition TPaveText.h:49
Basic string class.
Definition TString.h:136
Ssiz_t Length() const
Definition TString.h:410
const char * Data() const
Definition TString.h:369
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:2331
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:1589
virtual TString GetFromPipe(const char *command)
Execute command and return output in TString.
Definition TSystem.cxx:681
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:417
Base class for several text objects.
Definition TText.h:22
virtual TText * DrawText(Double_t x, Double_t y, const char *text)
Draw this text with new coordinates.
Definition TText.cxx:175
virtual void SetNDC(Bool_t isNDC=kTRUE)
Set NDC mode on if isNDC = kTRUE, off otherwise.
Definition TText.cxx:813
A TTree represents a columnar dataset.
Definition TTree.h:79
return c1
Definition legend1.C:41
return c2
Definition legend2.C:14
double T(double x)
Double_t Mean(Long64_t n, const T *a, const Double_t *w=0)
Return the weighted mean of an array a with length n.
Definition TMath.h:1073
Double_t RMS(Long64_t n, const T *a, const Double_t *w=0)
Return the Standard Deviation of an array a with length n.
Definition TMath.h:1167
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Definition TMathBase.h:362