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);