Hello
Sorry to come back on the memory leak, but i’m more than just confused with the latest test I’ve
done recently. It is, in a way, a follow-up of the discussion started about a year ago here:
Sorry also, because this is going to be quite a long post. In the rest of this post I’ll calling
leaks every complains coming from valgrind disregarding whether they’re marked in a suppression file
or not. This is not a criticism, but a shortcut for the sake of simplicity.
To recall, we are relying on ROOT for data handling and some of the graphical aspect and we are
developping another platform on top. We have a large bunch of unitary tests which are run every
night, allowing us to get the coverage of our code and to test the memory leak through valgrind
usage. In order to be efficient, we hope to get as few memory leaks as possible, with a constant
behaviour through time (as long as nothing as changed in our repository and prerequisite). In our
code we are using graphical methods and this was the origin of my question in the post shown above.
I’m currently getting back to these tests now that we are about to switch to root_v6, which is a big
leap (of faith ?) for us. Seeing the results of the valgrind job (sic!) I went back to a dummy
example comparing version 5 (v5.34/36) and 6 (v6.08/00). The dummy code under consideration is the
one below:
#include "TTree.h"
#include "TH1F.h"
#include "TCanvas.h"
#include <iostream>
using namespace std;
enum TOBEDONE{TREE=0, CANVAS, PLOT, HISTO};
int main(int argc, char** argv)
{
int value=0;
if(argc>1)
{
value=atoi(argv[1]);
if( value != 0 && value != 1 && value != 2 && value != 3 && value != 5 && value != 7 && value != 15)
{
cout<<"The command is either 1 for tree creation, 2 for canvas creation, 3 for both."<<endl;
cout<<" 5 will draw the tree without canvas while 7 will do everything and 15 will plot in a TH1F"<<endl;
return 0;
}
}
TTree *tt = NULL;
TCanvas *C = NULL;
TH1F *h=NULL;
if( value & 0x1 << TREE )
{
cout<<"create tree"<<endl;
tt = new TTree("tt","");
}
if( value & 0x1 << CANVAS )
{
cout<<"create canvas"<<endl;
C = new TCanvas("C","C",1);
}
if( value & 0x1 << TREE && value & 0x1 << PLOT )
{
cout<<"fill and plot tree"<<endl;
double pouet, pouet2;
tt->Branch("pouet",&pouet,"pouet/D");
tt->Branch("pouet2",&pouet2,"pouet2/D");
for(unsigned int i=0; i<100; i++)
{
pouet=i;
pouet2=float(i)/10;
tt->Fill();
}
if( value & 0x1 << HISTO )
{
cout<<"create histo"<<endl;
h = new TH1F("htest", "", 1000, 0, 150);
tt->Draw("pouet>>htest");
}
else
tt->Draw("pouet");
}
if( value & 0x1 << TREE && value & 0x1 << PLOT && value & 0x1 << HISTO )
delete h;
if( value & 0x1 << CANVAS )
delete C;
if( value & 0x1 << TREE )
delete tt;
}
the concept is that once compiled it can:
** do nothing ==> ARGUMENT = 0
** create a tree (and delete it) ==> ARGUMENT = 1
** create a Canvas (and delete it) ==> ARGUMENT = 2
** create a tree, a Canvas (and delete them) ==> ARGUMENT = 3
** create a tree, fill it and draw the results without canvas creation (and delete it) ==> ARGUMENT = 5
** do everyting ==> ARGUMENT = 7
** do everyting putting the plot in a TH1F ==> ARGUMENT = 15
In order to sum up properly this, I’m using the provided piece of shell-code both for v5 and v6 (it
compiles, run the jobs and dump the logs in output files).
#!/bin/sh
root_version=`root-config --version`
output_file="valgrind_v"
if [[ ${root_version:0:1} == "5" ]] ; then
echo $root_version
g++ -g -o v5PlottingTest PlottingTest.C `root-config --cflags --evelibs`
touch $output_file"5.txt"
for i in {0,1,2,3,5,7,15}
do
valgrind --leak-check=full --suppressions=${ROOTSYS}/etc/valgrind-root.supp ./v5PlottingTest $i &>> $output_file"5.txt"
echo ""&>> $output_file"5.txt"
echo ""&>> $output_file"5.txt"
done
elif [[ ${root_version:0:1} == "6" ]] ; then
echo $root_version
g++ -g -o v6PlottingTest PlottingTest.C `root-config --cflags --evelibs`
valgrind --leak-check=full --suppressions=${ROOTSYS}/etc/valgrind-root.supp ./v6PlottingTest $i &> $output_file"6_emptycode.txt"
touch $output_file"6_npl.txt"
for i in {0,1,2,3,5,7,15}
do
valgrind --leak-check=full --show-possibly-lost=no --suppressions=${ROOTSYS}/etc/valgrind-root.supp ./v6PlottingTest $i &>> $output_file"6_npl.txt"
echo ""&>> $output_file"6_npl.txt"
echo ""&>> $output_file"6_npl.txt"
done
fi
The results are joined and discussed here. For root v5, I’m testing all configurations and dumping
the logs in valgrind_v5.txt. There is one stated memory leak when nothing is done at all (it is
removed if the library are not linked in the compilation after commenting out every lines in
connection to ROOT). The results is equivalent if the tree is created and deleted. The first
question I have is when I just create a canvas (ARGUMENT==2): there is 7 leaks popping up. It seems
to me that it complains about the canvas-deletion step, but if I remove this It’ll complain about
not doing it anymore. Finally if one compares the stack when plotting the data with or without the
canvas creation, it leads to the same 9 leaks (which can be reduced to 8 if dumping the plot in an
already created TH1F and deleting it at the end of the job ==> ARGUMENT 15).
**** Do you know where does this behaviour comes from ?
I know that you told me to move to root v6 so this is what I did as well. Running the same macro on
v6, gives me a very (very) large log file (see valgrind_v6_emptycode.txt which is the results of the
empty code, ARGUMENT 0, which is not attached cause considered to big). First question then : are
you aware of that and is this normal ? I’ve run all the configurations discussed above but asking
to remove the possibly lost category to try to see something. This is the other output file
(valgrind_v6_npl.txt) which is way smaller (:D). When doing nothing there are 3 leaks stated but as
soon as some graphical methods are called, there are not there anymore and only a conditionnal jump
statement is made. Same question as before: are you aware of that and is this normal ?
The final question would be more on the stategy to adopt. I have the feeling that I should use the
–show-possibly-lost=no on root v6 but I don’t really like the idea: my main worry is not to hunt
down ROOT memory leak (I trust you to do that more efficiently that I’d ever do) but to find the
ones we are adding on top. I’m a bit worried that using this option, might hide some of our
mistakes. Also I’m wondering whether this option is made just to prevent the dumping on screen of
the leaks under consideration : on the contrary to a suppression file where the leaks are masked
(like in valgrind_v5.txt), the total counter of leaks in valgrind_v6_npl.txt is increasing when
testing the configurations (and the number is huge). Have you changed your strategy concerning the
valgrind suppression file ? What would you recommand ?
Any idea of I might be doing wrong ? Maybe I should not try to delete the canvas (and I"ve tried
many option to do so) but it leads to the same results (in v5).
Once again I’m sorry if this is a messy post, I’ve tried to simplify my problem but I’m pretty sure
I’ve failed.
cheers
jb
valgrind_v6_npl.txt (23.2 KB)
valgrind_v5.txt (70.2 KB)