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
or in an interactive session do something like:
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.
- In canvas1 it displays a dynamic histogram showing for pages (10 kbytes by default) the percentage of the page used. A summary pave shows the total memory still in use when the TMemStat object goes out of scope and the average occupancy of the pages. The average occupancy gives a good indication of the memory fragmentation.
- In canvas2 it displays the histogram of memory leaks in decreasing order. when moving the mouse on this canvas, a tooltip shows the backtrace for the leak in the bin below the mouse.
The script can be executed simply as
root > .x memstat.C (or via ACLIC .x memstat.C+ )
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.
�yX�*
Processing /mnt/build/workspace/root-makedoc-v612/rootspi/rdoc/src/v6-12-00-patches/tutorials/memstat/memstatExample.C...
Analyzing file: (null)
Cannot open file (null)
void memstatExample(
double update=0.01,
const char* fname=
"*") {
if (!fname || strlen(fname) <5 || strstr(fname,"*")) {
fname = strstr(s.
Data()+ns-25,
"memstat");
}
printf("Analyzing file: %s\n",fname);
if (!f) {
printf("Cannot open file %s\n",fname);
return;
}
if (!T) {
printf("cannot find the TMemStat TTree named T in file %s\n",fname);
return;
}
printf(
"Illegal update value %g, changed to 0.01\n",
update);
}
if (
update < 0.001) printf(
"Warning update parameter is very small, processing may be slow\n");
imean = imean - imean%bw;
irms = irms -irms%bw;
if (ivmax > 2000000000 && ivmin <2000000000) {
printf("memory locations above 2GBytes will be ignored\n");
nsel = T->
Draw(
"pos:nbytes:time:btid",
"pos <2e9",
"goff");
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;
}
memset(nbold,0,nvm*8);
h =
new TH1D(
"h",
Form(
"%s;pos;per cent of pages used",fname),nbins,ivmin,ivmax);
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);
for (i=0;i<nsel;i++) {
pos = V1[i];
time = 0.0001*V3[i];
if (bin<1 || bin>nbins) continue;
if (nbytes > 0) {
if (dbin > nbytes) dbin = nbytes;
nb =
Int_t((nbytes-dbin)/dv);
if (bin+nb >nbins) nb = nbins-bin;
rest = nbytes-nb*dv-dbin;
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++;
ientry[ipos] = i;
}
nbold[ipos] = nbytes;
} else {
nbytes = nbold[ipos];
if (bin+nb >nbins) nb = nbins-bin;
nbold[ipos] = 0; nleaks--;
if (nbytes <= 0) continue;
if (dbin > nbytes) dbin = nbytes;
nb =
Int_t((nbytes-dbin)/dv);
if (bin+nb >nbins) nb = nbins-bin;
rest = nbytes-nb*dv-dbin;
}
if (time -updateLast >
update) {
updateLast = time;
for (
Int_t k=1;k<nbins;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)");
}
}
nleaks += 1000;
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;
}
}
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++) {
i = entry[kk];
}
c2->
Connect(
"ProcessedEvent(Int_t, Int_t, Int_t, TObject*)",
0, 0, "EventInfo(Int_t, Int_t, Int_t, TObject*)");
}
{
if (!gTip) return;
return;
if (!hbtids) return;
if (!btidlist) return;
for (
Int_t i=0;i<nbt;i++) {
if (nm==0) break;
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;
}
if (selected) {
TString form1 =
TString::Format(
" Leak number=%d, leaking %d bytes at entry=%d time=%gseconds\n\n",bin,nbytes,entry,time);
}
}
- Author
- Rene Brun 7 July 2010
Definition in file memstatExample.C.