Logo ROOT   6.18/05
Reference Guide
memstatExample.C File Reference

Detailed Description

Script post-processing the file generated by TMemStat (default memstat.root)

To use the class TMemStat, add the following statement at the beginning of your script or program

TMemStat mm("gnubuiltin");
static constexpr double mm

or in an interactive session do something like:

root > TMemStat mm("gnubuiltin");
root > .x somescript.C
root > .q

TMemStat records all the calls to malloc and free and write a TTree with the position where the memory is allocated/freed , as well as the number of bytes.

This script creates 2 canvases.

The script can be executed simply as

root > .x memstat.C (or via ACLIC .x memstat.C+ )
Double_t x[n]
Definition: legend1.C:17

or specifying arguments

root > .x memstat.C+(0.01,"mydir/mymemstat.root");

The first argument to the script is the percentage of the time of the original job that produced the file after which the display is updated. By default update=0.01, ie 100 time intervals will be shown. The second argument is the input file name (result of TMemStat). If this argument is omitted, the script will take the most recent file generated by TMemStat.

Analyzing file: (null)
Cannot open file (null)
#include "TMath.h"
#include "TFile.h"
#include "TTree.h"
#include "TCanvas.h"
#include "TStyle.h"
#include "TH1.h"
#include "TPaveText.h"
#include "TPaveLabel.h"
#include "TSystem.h"
#include "TGClient.h"
#include "TGToolTip.h"
#include "TRootCanvas.h"
TH1D *halloc, *hfree;
TH1I *hleaks, *hentry;
TGToolTip *gTip = 0;
TObjArray *btidlist=0;
Double_t *V1, *V2, *V3, *V4;
void EventInfo(Int_t event, Int_t px, Int_t py, TObject *selected);
void memstatExample(double update=0.01, const char* fname="*") {
// Open the memstat data file, then call TTree::Draw to precompute
// the arrays of positions and nbytes per entry.
// update is the time interval in the data file in seconds after which
// the display is updated. For example is the job producing the memstat.root file
// took 100s to execute, an update of 0.1s will generate 1000 time views of
// the memory use.
// if fname=="*" (default), the most recent file memstat*.root will be taken.
if (!fname || strlen(fname) <5 || strstr(fname,"*")) {
//take the most recent file memstat*.root
s = gSystem->GetFromPipe("ls -lrt memstat*.root");
Int_t ns = s.Length();
fname = strstr(s.Data()+ns-25,"memstat");
}
printf("Analyzing file: %s\n",fname);
f = TFile::Open(fname);
if (!f) {
printf("Cannot open file %s\n",fname);
return;
}
T = (TTree*)f->Get("T");
if (!T) {
printf("cannot find the TMemStat TTree named T in file %s\n",fname);
return;
}
if (update <= 0) {
printf("Illegal update value %g, changed to 0.01\n",update);
update = 0.01;
}
if (update < 0.001) printf("Warning update parameter is very small, processing may be slow\n");
Long64_t nentries = T->GetEntries();
T->SetEstimate(nentries+10);
Long64_t nsel = T->Draw("pos:nbytes:time:btid","","goff");
//now we compute the best binning for the histogram
Int_t nbytes;
Double_t pos;
V1 = T->GetV1();
V2 = T->GetV2();
V3 = T->GetV3();
V4 = T->GetV4();
Long64_t imean = (Long64_t)TMath::Mean(nsel,V1);
Long64_t irms = (Long64_t)TMath::RMS(nsel,V1);
//Long64_t bw = 10000;
Long64_t bw = 1000;
imean = imean - imean%bw;
irms = irms -irms%bw;
Int_t nbins = Int_t(4*irms/bw);
Long64_t ivmin = imean -bw*nbins/2;
Long64_t ivmax = ivmin+bw*nbins;
if (ivmax > 2000000000 && ivmin <2000000000) {
//the data set has been likely generated on a 32 bits machine
//we are mostly interested by the small allocations, so we select
//only values below 2 GBytes
printf("memory locations above 2GBytes will be ignored\n");
nsel = T->Draw("pos:nbytes:time:btid","pos <2e9","goff");
V1 = T->GetV1();
V2 = T->GetV2();
V3 = T->GetV3();
V4 = T->GetV4();
imean = (Long64_t)TMath::Mean(nsel,V1);
irms = (Long64_t)TMath::RMS(nsel,V1);
bw = 10000;
imean = imean - imean%bw;
irms = irms -irms%bw;
nbins = Int_t(4*irms/bw);
ivmin = imean -bw*nbins/2;
ivmax = ivmin+bw*nbins;
}
update *= 0.0001*V3[nsel-1]; //convert time per cent in seconds
Long64_t nvm = Long64_t(ivmax-ivmin+1);
Long64_t *nbold = new Long64_t[nvm];
Int_t *ientry = new Int_t[nvm];
memset(nbold,0,nvm*8);
Double_t dv = (ivmax-ivmin)/nbins;
h = new TH1D("h",Form("%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax);
TAxis *axis = h->GetXaxis();
h->SetFillColor(kRed);
h->SetMinimum(0);
h->SetMaximum(100);
halloc = new TH1D("halloc",Form("%s;pos;number of mallocs",fname),nbins,ivmin,ivmax);
hfree = new TH1D("hfree", Form("%s;pos;number of frees",fname),nbins,ivmin,ivmax);
//open a canvas and draw the empty histogram
TCanvas *c1 = new TCanvas("c1","c1",1200,600);
c1->SetFrameFillColor(kYellow-3);
c1->SetGridx();
c1->SetGridy();
h->Draw();
//create a TPaveText to show the summary results
TPaveText *pvt = new TPaveText(.5,.9,.75,.99,"brNDC");
pvt->Draw();
//create a TPaveLabel to show the time
TPaveLabel *ptime = new TPaveLabel(.905,.7,.995,.76,"time","brNDC");
ptime->SetFillColor(kYellow-3);
ptime->Draw();
//draw producer identifier
TNamed *named = (TNamed*)T->GetUserInfo()->FindObject("SysInfo");
TText tmachine;
tmachine.SetTextSize(0.02);
tmachine.SetNDC();
if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
//start loop on selected rows
Int_t bin,nb=0,j;
Long64_t ipos;
Double_t dbin,rest,time;
Double_t updateLast = 0;
Int_t nleaks = 0;
Int_t i;
for (i=0;i<nsel;i++) {
pos = V1[i];
ipos = (Long64_t)(pos-ivmin);
nbytes = (Int_t)V2[i];
time = 0.0001*V3[i];
bin = axis->FindBin(pos);
if (bin<1 || bin>nbins) continue;
dbin = axis->GetBinUpEdge(bin)-pos;
if (nbytes > 0) {
halloc->Fill(pos);
if (dbin > nbytes) dbin = nbytes;
//fill bytes in the first page
h->AddBinContent(bin,100*dbin/dv);
//fill bytes in full following pages
nb = Int_t((nbytes-dbin)/dv);
if (bin+nb >nbins) nb = nbins-bin;
for (j=1;j<=nb;j++) h->AddBinContent(bin+j,100);
//fill the bytes remaining in last page
rest = nbytes-nb*dv-dbin;
if (rest > 0) h->AddBinContent(bin+nb+1,100*rest/dv);
//we save nbytes at pos. This info will be used when we free this slot
if (nbold[ipos] > 0) printf("reallocating %d bytes (was %lld) at %lld, entry=%d\n",nbytes,nbold[ipos],ipos,i);
if (nbold[ipos] == 0) {
nleaks++;
//save the Tree entry number where we made this allocation
ientry[ipos] = i;
}
nbold[ipos] = nbytes;
} else {
hfree->Fill(pos);
nbytes = nbold[ipos];
if (bin+nb >nbins) nb = nbins-bin;
nbold[ipos] = 0; nleaks--;
if (nbytes <= 0) continue;
//fill bytes free in the first page
if (dbin > nbytes) dbin = nbytes;
h->AddBinContent(bin,-100*dbin/dv);
//fill bytes free in full following pages
nb = Int_t((nbytes-dbin)/dv);
if (bin+nb >nbins) nb = nbins-bin;
for (j=1;j<=nb;j++) h->AddBinContent(bin+j,-100);
//fill the bytes free in in last page
rest = nbytes-nb*dv-dbin;
if (rest > 0) h->AddBinContent(bin+nb+1,-100*rest/dv);
}
if (time -updateLast > update) {
//update canvas at regular intervals
updateLast = time;
h->SetEntries(i);
c1->Modified();
Double_t mbytes = 0;
Int_t nonEmpty = 0;
for (Int_t k=1;k<nbins;k++) {
w = h->GetBinContent(k);
if (w > 0) {
nonEmpty++;
mbytes += 0.01*w*dv;
}
}
Double_t occupancy = mbytes/(nonEmpty*0.01*dv);
pvt->AddText(Form("memory used = %g Mbytes",mbytes*1e-6));
pvt->AddText(Form("page occupancy = %f per cent",occupancy));
pvt->AddText("(for non empty pages only)");
ptime->SetLabel(Form("%g sec",time));
c1->Update();
}
}
h->SetEntries(nsel);
Int_t nlmax = nleaks;
nleaks += 1000;
Int_t *lindex = new Int_t[nleaks];
Int_t *entry = new Int_t[nleaks];
Int_t *ileaks = new Int_t[nleaks];
nleaks =0;
for (Int_t ii=0;ii<nvm;ii++) {
if (nbold[ii] > 0) {
ileaks[nleaks] = (Int_t)nbold[ii];
entry[nleaks] = ientry[ii];
nleaks++;
if (nleaks > nlmax) break;
}
}
TMath::Sort(nleaks,ileaks,lindex);
hentry = new TH1I("hentry","leak entry index",nleaks,0,nleaks);
hleaks = new TH1I("hleaks","leaks;leak number;nbytes in leak",nleaks,0,nleaks);
for (Int_t k=0;k<nleaks;k++) {
Int_t kk = lindex[k];
i = entry[kk];
hentry->SetBinContent(k+1,i);
hleaks->SetBinContent(k+1,ileaks[kk]);
}
hentry->SetEntries(nleaks);
hleaks->SetEntries(nleaks);
//open a second canvas and draw the histogram with leaks in decreasing order
TCanvas *c2 = new TCanvas("c2","c2",1200,600);
c2->SetFrameFillColor(kCyan-6);
c2->SetGridx();
c2->SetGridy();
c2->SetLogy();
hleaks->SetFillColor(kRed-3);
if (nleaks > 1000) hleaks->GetXaxis()->SetRange(1,1000);
hleaks->Draw();
//draw producer identifier
if (named) tmachine.DrawText(0.01,0.01,named->GetTitle());
//construct the tooltip
TRootCanvas *rc = (TRootCanvas *)c2->GetCanvasImp();
TGMainFrame *frm = dynamic_cast<TGMainFrame *>(rc);
// create the tooltip with a timeout of 250 ms
if (!gTip) gTip = new TGToolTip(gClient->GetDefaultRoot(), frm, "", 250);
c2->Connect("ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
0, 0, "EventInfo(Int_t, Int_t, Int_t, TObject*)");
}
//______________________________________________________________________
void EventInfo(Int_t event, Int_t px, Int_t , TObject *selected)
{
//draw the tooltip showing the backtrace for the bin at px
if (!gTip) return;
gTip->Hide();
if (event == kMouseLeave)
return;
Double_t xpx = gPad->AbsPixeltoX(px);
Int_t bin = hleaks->GetXaxis()->FindBin(xpx);
if (bin <=0 || bin > hleaks->GetXaxis()->GetNbins()) return;
Int_t nbytes = (Int_t)hleaks->GetBinContent(bin);
Int_t entry = (Int_t)hentry->GetBinContent(bin);
Int_t btid = (Int_t)V4[entry];
Double_t time = 0.0001*V3[entry];
TH1I *hbtids = (TH1I*)T->GetUserInfo()->FindObject("btids");
if (!hbtids) return;
if (!btidlist) btidlist = (TObjArray*)T->GetUserInfo()->FindObject("FAddrsList");
if (!btidlist) btidlist = (TObjArray*)f->Get("FAddrsList"); //old memstat files
if (!btidlist) return;
Int_t nbt = (Int_t)hbtids->GetBinContent(btid-1);
TString ttip;
for (Int_t i=0;i<nbt;i++) {
Int_t j = (Int_t)hbtids->GetBinContent(btid+i);
TNamed *nm = (TNamed*)btidlist->At(j);
if (nm==0) break;
char *title = (char*)nm->GetTitle();
Int_t nch = strlen(title);
if (nch < 20) continue;
if (nch > 100) title[100] =0;
const char *bar = strstr(title,"| ");
if (!bar) continue;
if (strstr(bar,"operator new")) continue;
if (strstr(bar,"libMemStat")) continue;
if (strstr(bar,"G__Exception")) continue;
ttip += TString::Format("%2d %s\n",i,bar+1);
}
if (selected) {
TString form1 = TString::Format(" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time);
gTip->SetText(TString::Format("%s%s",form1.Data(),ttip.Data() ));
gTip->SetPosition(px+15, 100);
gTip->Reset();
}
}
@ 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:41
double Double_t
Definition: RtypesCore.h:55
long long Long64_t
Definition: RtypesCore.h:69
@ kRed
Definition: Rtypes.h:64
@ kCyan
Definition: Rtypes.h:64
@ kYellow
Definition: Rtypes.h:64
#define gClient
Definition: TGClient.h:166
int nentries
Definition: THbookFile.cxx:89
char * Form(const char *fmt,...)
R__EXTERN TStyle * gStyle
Definition: TStyle.h:406
R__EXTERN TSystem * gSystem
Definition: TSystem.h:560
#define gPad
Definition: TVirtualPad.h:286
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:279
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 from bin first to last.
Definition: TAxis.cxx:903
virtual Double_t GetBinUpEdge(Int_t bin) const
Return up edge of bin.
Definition: TAxis.cxx:514
The Canvas class.
Definition: TCanvas.h:31
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format.
Definition: TFile.h:48
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=ROOT::RCompressionSetting::EDefaults::kUseGeneralPurpose, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3980
void Hide()
Hide tool tip window.
Definition: TGToolTip.cxx:246
void SetPosition(Int_t x, Int_t y)
Set popup position within specified frame (as specified in the ctor).
Definition: TGToolTip.cxx:405
void SetText(const char *new_text)
Set new tool tip text.
Definition: TGToolTip.cxx:386
void Reset()
Reset tool tip popup delay timer.
Definition: TGToolTip.cxx:259
1-D histogram with a double per channel (see TH1 documentation)}
Definition: TH1.h:614
1-D histogram with an int per channel (see TH1 documentation)}
Definition: TH1.h:530
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition: TH1.h:316
virtual Int_t Fill(Double_t x)
Increment bin with abscissa X by 1.
Definition: TH1.cxx:3258
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:8635
virtual void Draw(Option_t *option="")
Draw this histogram with options.
Definition: TH1.cxx:2981
virtual Double_t GetBinContent(Int_t bin) const
Return content of bin number bin.
Definition: TH1.cxx:4882
virtual void SetEntries(Double_t n)
Definition: TH1.h:381
virtual void Delete(Option_t *option="")
Remove all objects from the list AND delete all heap based objects.
Definition: TList.cxx:467
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.
Definition: TPaveLabel.cxx:77
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.
Definition: TPaveText.cxx:182
virtual void Draw(Option_t *option="")
Draw this pavetext with its current attributes.
Definition: TPaveText.cxx:233
virtual TList * GetListOfLines() const
Definition: TPaveText.h:49
Basic string class.
Definition: TString.h:131
const char * Data() const
Definition: TString.h:364
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:2311
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:1444
virtual TString GetFromPipe(const char *command)
Execute command and return output in TString.
Definition: TSystem.cxx:689
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:425
Base class for several text objects.
Definition: TText.h:23
virtual TText * DrawText(Double_t x, Double_t y, const char *text)
Draw this text with new coordinates.
Definition: TText.cxx:174
virtual void SetNDC(Bool_t isNDC=kTRUE)
Set NDC mode on if isNDC = kTRUE, off otherwise.
Definition: TText.cxx:812
A TTree represents a columnar dataset.
Definition: TTree.h:71
return c1
Definition: legend1.C:41
return c2
Definition: legend2.C:14
double T(double x)
Definition: ChebyshevPol.h:34
static constexpr double bar
static constexpr double nm
static constexpr double s
static constexpr double ns
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:1061
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:1155
void Sort(Index n, const Element *a, Index *index, Bool_t down=kTRUE)
Definition: TMathBase.h:362
Author
Rene Brun 7 July 2010

Definition in file memstatExample.C.