00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "TMath.h"
00040 #include "TFile.h"
00041 #include "TTree.h"
00042 #include "TCanvas.h"
00043 #include "TStyle.h"
00044 #include "TH1.h"
00045 #include "TPaveText.h"
00046 #include "TPaveLabel.h"
00047 #include "TSystem.h"
00048 #include "TGClient.h"
00049 #include "TGToolTip.h"
00050 #include "TRootCanvas.h"
00051
00052 TFile *f;
00053 TTree *T;
00054 TH1D *h;
00055 TH1D *halloc, *hfree;
00056 TH1I *hleaks, *hentry;
00057 TGToolTip *gTip = 0;
00058 TObjArray *btidlist=0;
00059 Double_t *V1, *V2, *V3, *V4;
00060
00061 void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected);
00062
00063 void memstat(double update=0.01, const char* fname="*") {
00064
00065
00066
00067
00068
00069
00070
00071
00072 TString s;
00073 if (!fname || strlen(fname) <5 || strstr(fname,"*")) {
00074
00075 s = gSystem->GetFromPipe("ls -lrt memstat*.root");
00076 Int_t ns = s.Length();
00077 fname = strstr(s.Data()+ns-25,"memstat");
00078 }
00079 printf("Analyzing file: %s\n",fname);
00080 f = TFile::Open(fname);
00081 if (!f) {
00082 printf("Cannot open file %s\n",fname);
00083 return;
00084 }
00085 T = (TTree*)f->Get("T");
00086 if (!T) {
00087 printf("cannot find the TMemStat TTree named T in file %s\n",fname);
00088 return;
00089 }
00090 if (update <= 0) {
00091 printf("Illegal update value %g, changed to 0.01\n",update);
00092 update = 0.01;
00093 }
00094 if (update < 0.001) printf("Warning update parameter is very small, processing may be slow\n");
00095
00096
00097 Long64_t nentries = T->GetEntries();
00098 T->SetEstimate(nentries+10);
00099 Long64_t nsel = T->Draw("pos:nbytes:time:btid","","goff");
00100
00101
00102 Int_t nbytes;
00103 Double_t pos;
00104 V1 = T->GetV1();
00105 V2 = T->GetV2();
00106 V3 = T->GetV3();
00107 V4 = T->GetV4();
00108 Long64_t imean = (Long64_t)TMath::Mean(nsel,V1);
00109 Long64_t irms = (Long64_t)TMath::RMS(nsel,V1);
00110
00111 Long64_t bw = 1000;
00112 imean = imean - imean%bw;
00113 irms = irms -irms%bw;
00114 Int_t nbins = Int_t(4*irms/bw);
00115 Long64_t ivmin = imean -bw*nbins/2;
00116 Long64_t ivmax = ivmin+bw*nbins;
00117 if (ivmax > 2000000000 && ivmin <2000000000) {
00118
00119
00120
00121 printf("memory locations above 2GBytes will be ignored\n");
00122 nsel = T->Draw("pos:nbytes:time:btid","pos <2e9","goff");
00123 V1 = T->GetV1();
00124 V2 = T->GetV2();
00125 V3 = T->GetV3();
00126 V4 = T->GetV4();
00127 imean = (Long64_t)TMath::Mean(nsel,V1);
00128 irms = (Long64_t)TMath::RMS(nsel,V1);
00129 bw = 10000;
00130 imean = imean - imean%bw;
00131 irms = irms -irms%bw;
00132 nbins = Int_t(4*irms/bw);
00133 ivmin = imean -bw*nbins/2;
00134 ivmax = ivmin+bw*nbins;
00135 }
00136 update *= 0.0001*V3[nsel-1];
00137 Long64_t nvm = Long64_t(ivmax-ivmin+1);
00138 Long64_t *nbold = new Long64_t[nvm];
00139 Int_t *ientry = new Int_t[nvm];
00140 memset(nbold,0,nvm*8);
00141 Double_t dv = (ivmax-ivmin)/nbins;
00142 h = new TH1D("h",Form("%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax);
00143 TAxis *axis = h->GetXaxis();
00144 gStyle->SetOptStat("ie");
00145 h->SetFillColor(kRed);
00146 h->SetMinimum(0);
00147 h->SetMaximum(100);
00148 halloc = new TH1D("halloc",Form("%s;pos;number of mallocs",fname),nbins,ivmin,ivmax);
00149 hfree = new TH1D("hfree", Form("%s;pos;number of frees",fname),nbins,ivmin,ivmax);
00150
00151 TCanvas *c1 = new TCanvas("c1","c1",1200,600);
00152 c1->SetFrameFillColor(kYellow-3);
00153 c1->SetGridx();
00154 c1->SetGridy();
00155 h->Draw();
00156
00157 TPaveText *pvt = new TPaveText(.5,.9,.75,.99,"brNDC");
00158 pvt->Draw();
00159
00160 TPaveLabel *ptime = new TPaveLabel(.905,.7,.995,.76,"time","brNDC");
00161 ptime->SetFillColor(kYellow-3);
00162 ptime->Draw();
00163
00164 TNamed *named = (TNamed*)T->GetUserInfo()->FindObject("SysInfo");
00165 TText tmachine;
00166 tmachine.SetTextSize(0.02);
00167 tmachine.SetNDC();
00168 if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
00169
00170
00171 Int_t bin,nb=0,j;
00172 Long64_t ipos;
00173 Double_t dbin,rest,time;
00174 Double_t updateLast = 0;
00175 Int_t nleaks = 0;
00176 Int_t i;
00177 for (i=0;i<nsel;i++) {
00178 pos = V1[i];
00179 ipos = (Long64_t)(pos-ivmin);
00180 nbytes = (Int_t)V2[i];
00181 time = 0.0001*V3[i];
00182 bin = axis->FindBin(pos);
00183 if (bin<1 || bin>nbins) continue;
00184 dbin = axis->GetBinUpEdge(bin)-pos;
00185 if (nbytes > 0) {
00186 halloc->Fill(pos);
00187 if (dbin > nbytes) dbin = nbytes;
00188
00189 h->AddBinContent(bin,100*dbin/dv);
00190
00191 nb = Int_t((nbytes-dbin)/dv);
00192 if (bin+nb >nbins) nb = nbins-bin;
00193 for (j=1;j<=nb;j++) h->AddBinContent(bin+j,100);
00194
00195 rest = nbytes-nb*dv-dbin;
00196 if (rest > 0) h->AddBinContent(bin+nb+1,100*rest/dv);
00197
00198 if (nbold[ipos] > 0) printf("reallocating %d bytes (was %lld) at %lld, entry=%d\n",nbytes,nbold[ipos],ipos,i);
00199 if (nbold[ipos] == 0) {
00200 nleaks++;
00201
00202 ientry[ipos] = i;
00203 }
00204 nbold[ipos] = nbytes;
00205 } else {
00206 hfree->Fill(pos);
00207 nbytes = nbold[ipos];
00208 if (bin+nb >nbins) nb = nbins-bin;
00209 nbold[ipos] = 0; nleaks--;
00210 if (nbytes <= 0) continue;
00211
00212 if (dbin > nbytes) dbin = nbytes;
00213 h->AddBinContent(bin,-100*dbin/dv);
00214
00215 nb = Int_t((nbytes-dbin)/dv);
00216 if (bin+nb >nbins) nb = nbins-bin;
00217 for (j=1;j<=nb;j++) h->AddBinContent(bin+j,-100);
00218
00219 rest = nbytes-nb*dv-dbin;
00220 if (rest > 0) h->AddBinContent(bin+nb+1,-100*rest/dv);
00221
00222 }
00223 if (time -updateLast > update) {
00224
00225 updateLast = time;
00226 h->SetEntries(i);
00227 c1->Modified();
00228 pvt->GetListOfLines()->Delete();
00229 Double_t mbytes = 0;
00230 Int_t nonEmpty = 0;
00231 Double_t w;
00232 for (Int_t k=1;k<nbins;k++) {
00233 w = h->GetBinContent(k);
00234 if (w > 0) {
00235 nonEmpty++;
00236 mbytes += 0.01*w*dv;
00237 }
00238 }
00239 Double_t occupancy = mbytes/(nonEmpty*0.01*dv);
00240 pvt->AddText(Form("memory used = %g Mbytes",mbytes*1e-6));
00241 pvt->AddText(Form("page occupancy = %f per cent",occupancy));
00242 pvt->AddText("(for non empty pages only)");
00243 ptime->SetLabel(Form("%g sec",time));
00244
00245 c1->Update();
00246 gSystem->ProcessEvents();
00247 }
00248 }
00249 h->SetEntries(nsel);
00250 Int_t nlmax = nleaks;
00251 nleaks += 1000;
00252 Int_t *lindex = new Int_t[nleaks];
00253 Int_t *entry = new Int_t[nleaks];
00254 Int_t *ileaks = new Int_t[nleaks];
00255
00256 nleaks =0;
00257 for (Int_t ii=0;ii<nvm;ii++) {
00258 if (nbold[ii] > 0) {
00259 ileaks[nleaks] = (Int_t)nbold[ii];
00260 entry[nleaks] = ientry[ii];
00261 nleaks++;
00262 if (nleaks > nlmax) break;
00263 }
00264 }
00265
00266 TMath::Sort(nleaks,ileaks,lindex);
00267 hentry = new TH1I("hentry","leak entry index",nleaks,0,nleaks);
00268 hleaks = new TH1I("hleaks","leaks;leak number;nbytes in leak",nleaks,0,nleaks);
00269 for (Int_t k=0;k<nleaks;k++) {
00270 Int_t kk = lindex[k];
00271 i = entry[kk];
00272 hentry->SetBinContent(k+1,i);
00273 hleaks->SetBinContent(k+1,ileaks[kk]);
00274 }
00275 hentry->SetEntries(nleaks);
00276 hleaks->SetEntries(nleaks);
00277
00278
00279 TCanvas *c2 = new TCanvas("c2","c2",1200,600);
00280 c2->SetFrameFillColor(kCyan-6);
00281 c2->SetGridx();
00282 c2->SetGridy();
00283 c2->SetLogy();
00284 hleaks->SetFillColor(kRed-3);
00285 if (nleaks > 1000) hleaks->GetXaxis()->SetRange(1,1000);
00286 hleaks->Draw();
00287
00288 if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
00289
00290
00291 TRootCanvas *rc = (TRootCanvas *)c2->GetCanvasImp();
00292 TGMainFrame *frm = dynamic_cast<TGMainFrame *>(rc);
00293
00294 if (!gTip) gTip = new TGToolTip(gClient->GetDefaultRoot(), frm, "", 250);
00295 c2->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
00296 0, 0, "EventInfo(Int_t, Int_t, Int_t, TObject*)");
00297
00298 }
00299
00300
00301 void EventInfo(Int_t event, Int_t px, Int_t , TObject *selected)
00302 {
00303
00304 if (!gTip) return;
00305 gTip->Hide();
00306 if (event == kMouseLeave)
00307 return;
00308 Double_t xpx = gPad->AbsPixeltoX(px);
00309 Int_t bin = hleaks->GetXaxis()->FindBin(xpx);
00310 if (bin <=0 || bin > hleaks->GetXaxis()->GetNbins()) return;
00311 Int_t nbytes = (Int_t)hleaks->GetBinContent(bin);
00312 Int_t entry = (Int_t)hentry->GetBinContent(bin);
00313 Int_t btid = (Int_t)V4[entry];
00314 Double_t time = 0.0001*V3[entry];
00315 TH1I *hbtids = (TH1I*)T->GetUserInfo()->FindObject("btids");
00316 if (!hbtids) return;
00317 if (!btidlist) btidlist = (TObjArray*)T->GetUserInfo()->FindObject("FAddrsList");
00318 if (!btidlist) btidlist = (TObjArray*)f->Get("FAddrsList");
00319 if (!btidlist) return;
00320 Int_t nbt = (Int_t)hbtids->GetBinContent(btid-1);
00321 TString ttip;
00322 for (Int_t i=0;i<nbt;i++) {
00323 Int_t j = (Int_t)hbtids->GetBinContent(btid+i);
00324 TNamed *nm = (TNamed*)btidlist->At(j);
00325 if (nm==0) break;
00326 char *title = (char*)nm->GetTitle();
00327 Int_t nch = strlen(title);
00328 if (nch < 20) continue;
00329 if (nch > 100) title[100] =0;
00330 const char *bar = strstr(title,"| ");
00331 if (!bar) continue;
00332 if (strstr(bar,"operator new")) continue;
00333 if (strstr(bar,"libMemStat")) continue;
00334 if (strstr(bar,"G__Exception")) continue;
00335 ttip += TString::Format("%2d %s\n",i,bar+1);
00336 }
00337
00338 if (selected) {
00339 TString form1 = TString::Format(" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time);
00340 gTip->SetText(TString::Format("%s%s",form1.Data(),ttip.Data() ));
00341 gTip->SetPosition(px+15, 100);
00342 gTip->Reset();
00343 }
00344 }