106 TTree *TMemStatShow::fgT = 0;
107 TH1D *TMemStatShow::fgHalloc = 0;
108 TH1D *TMemStatShow::fgHfree = 0;
109 TH1D *TMemStatShow::fgH = 0;
110 TH1I *TMemStatShow::fgHleaks = 0;
111 TH1I *TMemStatShow::fgHentry = 0;
112 TH1I *TMemStatShow::fgHdiff = 0;
114 TGToolTip *TMemStatShow::fgTip1 = 0;
115 TGToolTip *TMemStatShow::fgTip2 = 0;
116 TObjArray *TMemStatShow::fgBtidlist = 0;
117 Double_t *TMemStatShow::fgV1 = 0;
118 Double_t *TMemStatShow::fgV2 = 0;
119 Double_t *TMemStatShow::fgV3 = 0;
120 Double_t *TMemStatShow::fgV4 = 0;
121 TCanvas *TMemStatShow::fgC1 = 0;
122 TCanvas *TMemStatShow::fgC2 = 0;
123 TCanvas *TMemStatShow::fgC3 = 0;
125 Long64_t TMemStatShow::fgEntryFirst = 0;
126 Long64_t TMemStatShow::fgEntryN = 0;
127 Long64_t TMemStatShow::fgAddressFirst = 0;
128 Long64_t TMemStatShow::fgAddressN = 0;
141 void TMemStatShow::SetAddressRange(Long64_t nbytes, Long64_t first)
143 fgAddressFirst = first;
155 void TMemStatShow::SetEntryRange(Long64_t nentries, Long64_t first)
157 fgEntryFirst = first;
172 void TMemStatShow::Show(
double update,
int nbigleaks,
const char* fname)
176 if (!fname || strlen(fname) <5 || strstr(fname,
"*")) {
178 s = gSystem->GetFromPipe(
"ls -lrt memstat*.root");
179 Int_t ns = s.Length();
180 fname = strstr(s.Data()+ns-25,
"memstat");
182 printf(
"Analyzing file: %s\n",fname);
183 TFile *f = TFile::Open(fname);
185 printf(
"Cannot open file %s\n",fname);
188 fgT = (TTree*)f->Get(
"T");
190 printf(
"cannot find the TMemStat TTree named T in file %s\n",fname);
194 printf(
"Illegal update value %g, changed to 0.01\n",update);
197 if (update < 0.001) printf(
"Warning update parameter is very small, processing may be slow\n");
201 gSystem->GetMemInfo(&minfo);
202 Int_t nfree = minfo.fMemTotal - minfo.fMemUsed;
203 printf(
"TMemStat::Show info: you are running on a machine with %d free MBytes of memory\n",nfree);
204 Long64_t nfreebytes = 200000*Long64_t(nfree);
205 if (fgAddressN <=0) fgAddressN = nfreebytes;
206 Long64_t nentries = fgT->GetEntries();
207 if (fgEntryN > 0 && nentries > fgEntryN) nentries = fgEntryN;
208 if (2*8*nentries > 4*nfreebytes) {
209 nentries = 4*nfreebytes/16;
210 printf(
"not enough memory, restricting analysis to %lld entries\n",nentries);
212 fgT->SetEstimate(nentries);
213 Long64_t nsel = fgT->Draw(
"pos",
"pos>0",
"goff",nentries);
215 Long64_t ivmin = (Long64_t)TMath::MinElement(nsel,fgV1);
216 Long64_t ivmax = (Long64_t)TMath::MaxElement(nsel,fgV1);
217 if (ivmax-ivmin > fgAddressN) ivmax = ivmin+fgAddressN;
218 printf(
"TMemStatShow::Show will analyze only %lld bytes in its first pass\n",ivmax);
226 Long64_t ne = nfreebytes/32LL;
227 if (ne < nentries) nentries = ne;
228 fgT->SetEstimate(nentries+10);
229 printf(
"sel: ivmin=%lld, ivmax=%lld, nentries=%lld\n",ivmin,ivmax,nentries);
230 nsel = fgT->Draw(
"pos:nbytes:time:btid",
231 TString::Format(
"pos>%g && pos<%g",Double_t(ivmin),Double_t(ivmax)),
232 "goff",nentries,fgEntryFirst);
241 ivmin = (Long64_t)TMath::MinElement(nsel,fgV1);
242 ivmax = (Long64_t)TMath::MaxElement(nsel,fgV1);
244 Double_t dvv = (Double_t(ivmax) - Double_t(ivmin))/Double_t(bw);
245 Long64_t nbins = Long64_t(dvv);
246 ivmin = ivmin -ivmin%bw;
247 ivmax = ivmin+bw*nbins;
248 Long64_t nvm = Long64_t(ivmax-ivmin+1);
249 printf(
"==>The data Tree contains %lld entries with addresses in range[%lld,%lld]\n",nsel,ivmin,ivmax);
251 ne = 1000000LL*nfree/32LL;
257 nsel = fgT->Draw(
"pos:nbytes:time:btid",
258 TString::Format(
"pos>=%g && pos<%g",Double_t(ivmin),Double_t(ivmax)),
"goff",ne,fgEntryFirst);
263 ivmin = (Long64_t)TMath::MinElement(nsel,fgV1);
264 ivmax = (Long64_t)TMath::MaxElement(nsel,fgV1);
266 dvv = (Double_t(ivmax) - Double_t(ivmin))/Double_t(bw);
267 nbins = Long64_t(dvv+0.5);
268 ivmin = ivmin -ivmin%bw;
269 ivmax = ivmin+bw*nbins;
270 printf(
"==>Address range or/and Entry range is too large\n");
271 printf(
"==>restricting the analysis range to [%lld,%lld] and %lld entries\n",ivmin,ivmax,ne);
272 printf(
"==>you can restrict the address range with TMemStatShow::SetAddressRange\n");
273 printf(
"==>you can restrict the entries range with TMemStatShow::SetEntryRange\n");
275 update *= 0.0001*fgV3[nsel-1];
276 nvm = Long64_t(ivmax-ivmin);
277 Long64_t *nbold =
new Long64_t[nvm];
278 Int_t *ientry =
new Int_t[nvm];
279 if (!nbold || !ientry) {
280 printf(
"you do not have enough memory to run, %lld bytes needed\n",12*nvm);
283 memset(nbold,0,nvm*8);
284 memset(ientry,0,nvm*4);
285 Double_t dv = (ivmax-ivmin)/nbins;
286 TH1D *h =
new TH1D(
"h",Form(
"%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax);
288 TAxis *axis = h->GetXaxis();
289 gStyle->SetOptStat(
"ie");
290 h->SetFillColor(kRed);
293 fgHalloc =
new TH1D(
"fgHalloc",Form(
"%s;pos;number of mallocs",fname),nbins,ivmin,ivmax);
294 fgHfree =
new TH1D(
"fgHfree", Form(
"%s;pos;number of frees",fname),nbins,ivmin,ivmax);
295 fgHdiff =
new TH1I(
"fgHdiff",
"",1000,0,1e5);
297 fgC1 =
new TCanvas(
"fgC1",
"c1",1200,600);
298 fgC1->SetFrameFillColor(kYellow-3);
303 TPaveText *pvt =
new TPaveText(.5,.9,.75,.99,
"brNDC");
306 TPaveLabel *ptime =
new TPaveLabel(.905,.7,.995,.76,
"time",
"brNDC");
307 ptime->SetFillColor(kYellow-3);
310 TNamed *named = (TNamed*)fgT->GetUserInfo()->FindObject(
"SysInfo");
312 tmachine.SetTextSize(0.02);
314 if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
319 Double_t dbin,rest,time;
320 Double_t updateLast = 0;
323 for (i=0;i<nsel;i++) {
325 ipos = (Long64_t)(pos-ivmin);
326 nbytes = (Int_t)fgV2[i];
327 time = 0.0001*fgV3[i];
328 bin = axis->FindBin(pos);
329 if (bin<1 || bin>nbins)
continue;
330 dbin = axis->GetBinUpEdge(bin)-pos;
334 if (dbin > nbytes) dbin = nbytes;
336 h->AddBinContent(bin,100*dbin/dv);
338 nb = Int_t((nbytes-dbin)/dv);
339 if (bin+nb >nbins) nb = nbins-bin;
340 for (j=1;j<=nb;j++) h->AddBinContent(bin+j,100);
342 rest = nbytes-nb*dv-dbin;
343 if (rest > 0) h->AddBinContent(bin+nb+1,100*rest/dv);
346 if (nbold[ipos] == 0) {
351 nbold[ipos] = nbytes;
354 nbytes = nbold[ipos];
355 if (bin+nb >nbins) nb = nbins-bin;
356 nbold[ipos] = 0; nleaks--;
357 fgHdiff->Fill(i-ientry[ipos]);
358 if (nbytes <= 0)
continue;
360 if (dbin > nbytes) dbin = nbytes;
361 h->AddBinContent(bin,-100*dbin/dv);
363 nb = Int_t((nbytes-dbin)/dv);
364 if (bin+nb >nbins) nb = nbins-bin;
365 for (j=1;j<=nb;j++) h->AddBinContent(bin+j,-100);
367 rest = nbytes-nb*dv-dbin;
368 if (rest > 0) h->AddBinContent(bin+nb+1,-100*rest/dv);
371 if (time -updateLast > update) {
376 pvt->GetListOfLines()->Delete();
380 for (Int_t k=1;k<nbins;k++) {
381 w = h->GetBinContent(k);
387 Double_t occupancy = mbytes/(nonEmpty*0.01*dv);
388 pvt->AddText(Form(
"memory used = %g Mbytes",mbytes*1e-6));
389 pvt->AddText(Form(
"page occupancy = %f per cent",occupancy));
390 pvt->AddText(
"(for non empty pages only)");
391 ptime->SetLabel(Form(
"%g sec",time));
394 gSystem->ProcessEvents();
398 if (nleaks < 0) nleaks=0;
399 Int_t nlmax = nleaks;
401 Int_t *lindex =
new Int_t[nleaks];
402 Int_t *entry =
new Int_t[nleaks];
403 Int_t *ileaks =
new Int_t[nleaks];
406 for (Int_t ii=0;ii<nvm;ii++) {
408 ileaks[nleaks] = (Int_t)nbold[ii];
409 entry[nleaks] = ientry[ii];
411 if (nleaks > nlmax)
break;
414 TMath::Sort(nleaks,ileaks,lindex);
415 fgHentry =
new TH1I(
"fgHentry",
"leak entry index",nleaks,0,nleaks);
416 fgHleaks =
new TH1I(
"fgHleaks",
"leaks;leak number;nbytes in leak",nleaks,0,nleaks);
417 for (Int_t k=0;k<nleaks;k++) {
418 Int_t kk = lindex[k];
420 fgHentry->SetBinContent(k+1,i);
421 fgHleaks->SetBinContent(k+1,ileaks[kk]);
428 fgHentry->SetEntries(nleaks);
429 fgHleaks->SetEntries(nleaks);
435 TRootCanvas *rc1 = (TRootCanvas *)fgC1->GetCanvasImp();
436 TGMainFrame *frm1 =
dynamic_cast<TGMainFrame *
>(rc1);
438 if (!fgTip1) fgTip1 =
new TGToolTip(gClient->GetDefaultRoot(), frm1,
"", 250);
439 fgC1->Connect(
"ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
440 "TMemStatShow", 0,
"EventInfo1(Int_t, Int_t, Int_t, TObject*)");
441 if (nbigleaks <= 0)
return;
445 fgC2 =
new TCanvas(
"fgC2",
"c2",1200,600);
446 fgC2->SetFrameFillColor(kCyan-6);
450 fgHleaks->SetFillColor(kRed-3);
451 if (nleaks > 1000) fgHleaks->GetXaxis()->SetRange(1,1000);
454 if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
457 TRootCanvas *rc2 = (TRootCanvas *)fgC2->GetCanvasImp();
458 TGMainFrame *frm2 =
dynamic_cast<TGMainFrame *
>(rc2);
460 if (!fgTip2) fgTip2 =
new TGToolTip(gClient->GetDefaultRoot(), frm2,
"", 250);
461 fgC2->Connect(
"ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
462 "TMemStatShow", 0,
"EventInfo2(Int_t, Int_t, Int_t, TObject*)");
466 fgC3 =
new TCanvas(
"fgC3",
"c3",1200,600);
467 fgC3->SetFrameFillColor(kCyan-6);
471 fgC3->SetLeftMargin(0.05);
472 fgC3->SetRightMargin(0.7);
476 TH1I *htotleaks =
new TH1I(
"htotleaks",
"main leaks sorted by btids",100,0,0);
478 for (l=1;l<=nleaks;l++) {
479 TString btstring =
"";
480 TMemStatShow::FillBTString(l,1,btstring);
481 htotleaks->Fill(btstring.Data()+2,fgHleaks->GetBinContent(l));
483 Double_t tsize = 0.03;
484 if (nbigleaks > 30) tsize = 0.02;
485 htotleaks->LabelsOption(
">");
486 htotleaks->GetXaxis()->SetRange(1,nbigleaks);
487 htotleaks->GetXaxis()->SetLabelSize(tsize);
488 htotleaks->GetYaxis()->SetLabelSize(tsize);
489 htotleaks->SetFillColor(kBlue-3);
490 htotleaks->Draw(
"hbar2 y+");
493 Double_t xr = 0.96*fgC3->GetLeftMargin();
494 Double_t xr2 = 1.04*fgC3->GetLeftMargin();
495 Double_t ytop = 1-fgC3->GetTopMargin();
496 Double_t ylow = fgC3->GetBottomMargin();
497 Double_t dy = (ytop-ylow)/nbigleaks;
501 tnl.SetTextSize(tsize);
502 tnl.SetTextAlign(32);
505 tnl2.SetTextSize(tsize);
506 tnl2.SetTextAlign(12);
507 tnl2.SetTextColor(kYellow);
508 for (Int_t lb=1;lb<=nbigleaks;lb++) {
509 if (htotleaks->GetBinContent(lb) <= 0)
continue;
510 const char *label = htotleaks->GetXaxis()->GetBinLabel(lb);
511 Int_t nchlabel = strlen(label);
512 if (nchlabel == 0) htotleaks->GetXaxis()->SetBinLabel(lb,
"???");
514 for (l=1;l<=nleaks;l++) {
516 TMemStatShow::FillBTString(l,1,btstring);
518 if (!strncmp(btstring.Data()+2,label,nchlabel)) nl++;
520 if (btstring.Length() == 0) nl++;
523 Double_t yr = ylow +(lb-0.5)*dy;
524 tnl.DrawText(xr,yr,Form(
"%d",nl));
525 Int_t nbmean = Int_t(htotleaks->GetBinContent(lb)/nl);
526 if (lb == 1) tnl2.DrawText(xr2,yr,Form(
"%d bytes/alloc",nbmean));
527 else tnl2.DrawText(xr2,yr,Form(
"%d",nbmean));
529 tnl.DrawText(xr,ytop+0.015,
"nallocs");
530 tnl.DrawText(1-fgC3->GetRightMargin(),0.5*ylow,
"nbytes");
532 if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
539 void TMemStatShow::EventInfo1(Int_t event, Int_t px, Int_t , TObject *selected)
543 if (event == kMouseLeave)
545 Double_t xpx = fgC1->AbsPixeltoX(px);
546 Double_t xpx1 = fgC1->AbsPixeltoX(px+1);
547 Int_t bin = fgH->GetXaxis()->FindBin(xpx);
548 Int_t bin1 = fgH->GetXaxis()->FindBin(xpx1);
550 while (bin <= bin1) {
551 if (fgH->GetBinContent(bin) > 0)
break;
554 if (fgH->GetBinContent(bin) <= 0)
return;
555 if (bin <=0 || bin > fgH->GetXaxis()->GetNbins())
return;
556 Double_t posmin = fgH->GetXaxis()->GetBinLowEdge(bin);
557 Double_t posmax = fgH->GetXaxis()->GetBinUpEdge(bin);
558 Int_t nsel = (Int_t)fgT->GetSelectedRows();
563 for (Int_t i=0;i<nsel;i++) {
564 if (fgV2[i] < 0)
continue;
565 if (fgV1[i] < posmax && fgV1[i]+fgV2[i] >posmin) {
567 nbytes = (Int_t)fgV2[i];
573 Double_t time = 0.0001*fgV3[entry];
575 TMemStatShow::FillBTString(entry,0,ttip);
578 TString form1 = TString::Format(
" Alloc(%d) at %lld of %d bytes, time=%gseconds\n\n",nhits,Long64_t(fgV1[entry]),nbytes,time);
579 fgTip1->SetText(TString::Format(
"%s%s",form1.Data(),ttip.Data() ));
580 fgTip1->SetPosition(px+15, 100);
588 void TMemStatShow::EventInfo2(Int_t event, Int_t px, Int_t , TObject *selected)
592 if (event == kMouseLeave)
594 Double_t xpx = fgC2->AbsPixeltoX(px);
595 Int_t bin = fgHleaks->GetXaxis()->FindBin(xpx);
596 if (bin <=0 || bin > fgHleaks->GetXaxis()->GetNbins())
return;
597 Int_t nbytes = (Int_t)fgHleaks->GetBinContent(bin);
598 Int_t entry = (Int_t)fgHentry->GetBinContent(bin);
599 Double_t time = 0.0001*fgV3[entry];
601 TMemStatShow::FillBTString(entry,0,ttip);
604 TString form1 = TString::Format(
" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time);
605 fgTip2->SetText(TString::Format(
"%s%s",form1.Data(),ttip.Data() ));
606 fgTip2->SetPosition(px+15, 100);
615 void TMemStatShow::FillBTString(Int_t entry,Int_t mode,TString &btstring)
617 Int_t btid = (Int_t)fgV4[entry];
618 TH1I *hbtids = (TH1I*)fgT->GetUserInfo()->FindObject(
"btids");
620 if (!fgBtidlist) fgBtidlist = (TObjArray*)fgT->GetUserInfo()->FindObject(
"FAddrsList");
621 if (!fgBtidlist) fgBtidlist = (TObjArray*)gFile->Get(
"FAddrsList");
622 if (!fgBtidlist)
return;
623 Int_t nbt = (Int_t)hbtids->GetBinContent(btid-1);
624 for (Int_t i=0;i<nbt;i++) {
625 Int_t j = (Int_t)hbtids->GetBinContent(btid+i);
626 TNamed *nm = (TNamed*)fgBtidlist->At(j);
628 char *title = (
char*)nm->GetTitle();
629 Int_t nch = strlen(title);
630 if (nch < 10)
continue;
631 if (strstr(title,
"malloc"))
continue;
632 if (strstr(title,
"memstat"))
continue;
633 if (strstr(title,
"TMemStatHook"))
continue;
634 char *bar = strchr(title+5,
'|');
635 if (!bar) bar = title;
637 if (strstr(bar,
"operator new"))
continue;
638 if (strstr(bar,
"libMemStat"))
continue;
639 if (strstr(bar,
"G__Exception"))
continue;
641 btstring += TString::Format(
"%s ",bar);
642 if (btstring.Length() > 80)
return;
644 btstring += TString::Format(
"%2d %s\n",i,bar+1);