Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RF] Problem of memory leak (?) with RooDataSet #8984

Closed
marcescalier opened this issue Sep 10, 2021 · 22 comments · Fixed by #12061
Closed

[RF] Problem of memory leak (?) with RooDataSet #8984

marcescalier opened this issue Sep 10, 2021 · 22 comments · Fixed by #12061

Comments

@marcescalier
Copy link

Describe the bug

I open a workspace (RooWorkspace) that contains a pdf and various parameters. From these I do a loop on pseudo-experiments ("toys") that generate a RooDataSet.

For each toy in the loop, after generation, I delete the RooDataset.

But the memory, as reported by the class ProcInfo_t, never decreases.

It means that either ProcInfo_t is not actually showing the current memory information, or that is shows the "integrated memory used since the beginning",
or that RooDataSet would have a memory leak ?
or that I have a bug in my program ?

I provide a minimum reproducible example.
See for example : "EXAMPLE OF PROBLEM"

The minimum program is here :
/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory

Expected behavior

the expected behaviour would be that when I delete the RooDataSet, the memory would reduce.

To Reproduce

The README shows the quick steps for allowing to read the root file

Setup

I used root 6.18.00 to reproduce the problem on a french cluster of computer

On lxplus, I reproduce the problem, with root 6.20.02

Additional context

@jalopezg-git
Copy link
Collaborator

Hi @marcescalier,

I have assigned this to Jonas; he will take a look as soon as he can. :-)

Cheers.

@marcescalier
Copy link
Author

Thank you. Good luck to Jonas if he finds time for the investigation.

@guitargeek guitargeek changed the title Problem of memory leak (?) with RooDataSet [RF] Problem of memory leak (?) with RooDataSet Dec 3, 2021
@marcescalier
Copy link
Author

Hello
Are there news ?

@marcescalier marcescalier reopened this Jan 17, 2023
@guitargeek
Copy link
Contributor

Hi, I'm glad you asked! I tried to reproduce this issue myself a few weeks ago actually, but I couldn't see the memory increase. Which ROOT version are you using?

If this is still a problem for you with the current ROOT version, I will continue the investigation.

@marcescalier
Copy link
Author

Thank you.
I was using root 6.18.00.

Which version of root do you use without having the problem ?

Could you check that in "EXAMPLE Of PROBLEM", you really have a decrease of memory consumption ?

I tried again (same problem)
-on lxplus, with root 6.20.02 : same problem
proof : the deletion of a RooDataSet does not reduce the memory consuption :

just after creation of dataset toy that uses previous toy per category
res memory=243.1718750000 Mbytes
vir memory=568.2500000000 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=243.3007812500 Mbytes
vir memory=568.2500000000 Mbytes

-on a french cluster of computer, with root 6.26.04 : same problem
just after creation of dataset toy that uses previous toy per category
res memory=315.2851562500 Mbytes
vir memory=711.7109375000 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=315.3359375000 Mbytes
vir memory=711.7109375000 Mbytes

@marcescalier
Copy link
Author

marcescalier commented Jan 18, 2023

To summarize : the problem is not a memory increase, but the fact that when we delete the RooDataSet,

so there is an intrinsic memory leak of roofit : the allocated memory is not given back to the system when we delete the RooDataset.

@guitargeek
Copy link
Contributor

Okay! Then it's very likely related to the memory pool, which will be disabled in ROOT 6.28 as of this PR:
#8324

Can you please try if you still see you problem with the ROOT nighlty build?
https://root.cern/install/nightlies/

@marcescalier
Copy link
Author

marcescalier commented Jan 18, 2023

I tried to setup a nightly version of root, following your suggestion :
source /cvmfs/sft.cern.ch/lcg/views/dev3/latest/x86_64-centos7-gcc8-opt/setup.sh

but this gives :
root --version
ROOT Version: 6.24/08

and then the program does not work

/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory] root -b -q "Minimum.C+()"
   ------------------------------------------------------------------
  | Welcome to ROOT 6.24/08                        https://root.cern |
  | (c) 1995-2021, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Sep 29 2022, 13:04:57                 |
  | From tags/v6-24-08@v6-24-08                                      |
  | With c++ (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)                 |
  | Try '.help', '.demo', '.license', '.credits', '.quit'/'.q'       |
   ------------------------------------------------------------------


Processing Minimum.C+()...
Info in <TUnixSystem::ACLiC>: creating shared library /afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/./Minimum_C.so
Warning in cling::IncrementalParser::CheckABICompatibility():
  Possible C++ standard library mismatch, compiled with __GLIBCXX__ '20150623'
  Extraction of runtime standard library version was: '20190222'

RooFit v3.60 -- Developed by Wouter Verkerke and David Kirkby
                Copyright (C) 2000-2013 NIKHEF, University of California & Stanford University
                All rights reserved, please read http://roofit.sourceforge.net/license.txt

cling::DynamicLibraryManager::loadLibrary(): /afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/Minimum_C.so: undefined symbol: _ZN5TROOT14RegisterModuleEPKcPS1_S2_S1_S1_PFvvERKSt6vectorISt4pairINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEiESaISD_EES2_b
/lib/../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/Minimum_C_ACLiC_dict.o: In function `(anonymous namespace)::TriggerDictionaryInitialization_Minimum_C_ACLiC_dict_Impl()':
/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/Minimum_C_ACLiC_dict.cxx:94: undefined reference to `TROOT::RegisterModule(char const*, char const**, char const**, char const*, char const*, void (*)(), std::vector<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int>, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int> > > const&, char const**, bool)'
/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/Minimum_C_ACLiC_dict.o: In function `Minimum()':
/usr/include/root/RooCategory.h:60: undefined reference to `RooCategory::defineType(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/Minimum_C_ACLiC_dict.o: In function `Minimum()':
/afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/./Minimum.C:307: undefined reference to `RooFit::Import(std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RooDataSet*, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, RooDataSet*> > > const&)'
collect2: error: ld returned 1 exit status

@guitargeek
Copy link
Contributor

Oh well, I don't know what's messed up with the environment. You tried on lxplus? For me it works:

   ------------------------------------------------------------------
  | Welcome to ROOT 6.29/01                        https://root.cern |
  | (c) 1995-2022, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for linuxx8664gcc on Jan 18 2023, 10:59:00                 |
  | From heads/master@v6-29-01-232-gbdd7e89922e                      |
  | With c++ (GCC) 12.2.0                                            |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0]
Processing Minimum.C...
Survey Memory, beginning of program
res memory=287.363 Mbytes
vir memory=343.223 Mbytes
Survey Memory, after open file
res memory=301.309 Mbytes
vir memory=390.062 Mbytes
Survey Memory, after read workspace file
res memory=314.93 Mbytes
vir memory=402.078 Mbytes
RooRealVar::XS_HH_res = 1 C  L(-INF - +INF)
Survey Memory, after read dataset workspace
res memory=314.93 Mbytes
vir memory=402.078 Mbytes
Survey Memory, after create output file
res memory=314.93 Mbytes
vir memory=402.078 Mbytes
RooArgSet:: = (XS_HH_res,mu,mu_HH,mu_ZH,mu_ttH,mu_ggH,mu_VBF_HH,mu_WH,mu_tWH,mu_tHjb,mu_bbH,mu_VBFH)


start of toys
phase 1
RooRealVar::xi = -0.0190762 +/- 0.0234282  L(-10 - 0)





index_toy=1
Survey Memory
res memory=314.93 Mbytes
vir memory=402.078 Mbytes
start randomization
tt->GetName()=resonant
pdftmp=0x55b9e4e91430
generate current category
just before generate
res memory=314.93 Mbytes
vir memory=402.078 Mbytes
just after generate
res memory=334.656 Mbytes
vir memory=423.648 Mbytes
toyDataMap[tt->GetName()]->numEntries()=45
toyDataMap[tt->GetName()]->sumEntries()=45
immediatly after generate
print the pdf
pdf=0x55b9e4e07720
RooSimultaneous::CombinedPdf[ indexCat=channellist resonant=_model_resonant ] = 3.03502e-17
printed the pdf
toy numEntries=45, toyData->numEntries()=45.0000000000
just after creation of dataset toy that uses previous toy per category
res memory=334.6562500000 Mbytes
vir memory=423.6484375000 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=334.6562500000 Mbytes
vir memory=423.6484375000 Mbytes
delete toyData
just after deletion of toyData
res memory=334.6562500000 Mbytes
vir memory=423.6484375000 Mbytes





index_toy=2
Survey Memory
res memory=334.656 Mbytes
vir memory=423.648 Mbytes
start randomization
tt->GetName()=resonant
pdftmp=0x55b9e4e91430
generate current category
just before generate
res memory=334.656 Mbytes
vir memory=423.648 Mbytes
just after generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
toyDataMap[tt->GetName()]->numEntries()=48
toyDataMap[tt->GetName()]->sumEntries()=48
immediatly after generate
print the pdf
pdf=0x55b9e4e07720
RooSimultaneous::CombinedPdf[ indexCat=channellist resonant=_model_resonant ] = 1.93479e-22
printed the pdf
toy numEntries=48, toyData->numEntries()=48.0000000000
just after creation of dataset toy that uses previous toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
delete toyData
just after deletion of toyData
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes





index_toy=3
Survey Memory
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
start randomization
tt->GetName()=resonant
pdftmp=0x55b9e4e91430
generate current category
just before generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
just after generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
toyDataMap[tt->GetName()]->numEntries()=43
toyDataMap[tt->GetName()]->sumEntries()=43
immediatly after generate
print the pdf
pdf=0x55b9e4e07720
RooSimultaneous::CombinedPdf[ indexCat=channellist resonant=_model_resonant ] = 1.85588e-20
printed the pdf
toy numEntries=43, toyData->numEntries()=43.0000000000
just after creation of dataset toy that uses previous toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
delete toyData
just after deletion of toyData
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes





index_toy=4
Survey Memory
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
start randomization
tt->GetName()=resonant
pdftmp=0x55b9e4e91430
generate current category
just before generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
just after generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
toyDataMap[tt->GetName()]->numEntries()=57
toyDataMap[tt->GetName()]->sumEntries()=57
immediatly after generate
print the pdf
pdf=0x55b9e4e07720
RooSimultaneous::CombinedPdf[ indexCat=channellist resonant=_model_resonant ] = 2.17115e-14
printed the pdf
toy numEntries=57, toyData->numEntries()=57.0000000000
just after creation of dataset toy that uses previous toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
delete toyData
just after deletion of toyData
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes





index_toy=5
Survey Memory
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
start randomization
tt->GetName()=resonant
pdftmp=0x55b9e4e91430
generate current category
just before generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
just after generate
res memory=335.289 Mbytes
vir memory=424.035 Mbytes
toyDataMap[tt->GetName()]->numEntries()=40
toyDataMap[tt->GetName()]->sumEntries()=40
immediatly after generate
print the pdf
pdf=0x55b9e4e07720
RooSimultaneous::CombinedPdf[ indexCat=channellist resonant=_model_resonant ] = 1.52722e-20
printed the pdf
toy numEntries=40, toyData->numEntries()=40.0000000000
just after creation of dataset toy that uses previous toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
delete toyData
just after deletion of toyData
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes
STOP PROGRAM
just before stop of program
res memory=335.2890625000 Mbytes
vir memory=424.0351562500 Mbytes

And in fact, the increase in memory is gone, right?

By the way, the RooArgSet you create in line 303 of your reproducer is leaking:

    RooArgSet* args = new RooArgSet(); // never deleted!

@marcescalier
Copy link
Author

ok : I don't know why root does not work for me (yes, I use lxplus).
As I said, the problem is not that there is not an increase : the problem is that when I delete memory of the RooDataSet, the memory has not decreased.
See this in your example :

just after creation of dataset toy that uses previous toy per category
res memory=334.6562500000 Mbytes
vir memory=423.6484375000 Mbytes
EXAMPLE OF PROBLEM : the memory does not decrease !
just after deletion of toy per category
res memory=334.6562500000 Mbytes
vir memory=423.6484375000 Mbytes
delete toyData
just after deletion of toyData
res memory=334.6562500000 Mbytes
vir memory=423.6484375000 Mbytes

You see that after deleting the dataset gives exactly the same memory as after having created the dataset, so there is a problem, isn't it ?!?

(thank you for the information about the RooArgSet * deletion)

@guitargeek
Copy link
Contributor

You see that after deleting the dataset gives exactly the same memory as after having created the dataset, so there is a problem, isn't it ?!?

I'm not convinced by this yet because I don't completely understand the output at this point. Yes, you are right, memory doesn't decrease, but starting from the third toy it also doesn't increase when generate() is called, right? So these numbers don't make sense to me to begin with, and I would rather not conclude that there is a memory leak based on

But anyway, I managed to convince myself by generating many more toys, and observing a steady memory increase over time. I did this with a simplified version of your reproducer:

void Minimum2()
{
   using namespace RooFit;
   using namespace RooStats;

   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::unique_ptr<TFile> f_ws{TFile::Open("WS-YY-resonant_500_For_Comb.root", "READ")};

   auto *ws = f_ws->Get<RooWorkspace>("combWS");
   auto *mc = static_cast<ModelConfig *>(ws->obj("ModelConfig"));
   auto *pdf = static_cast<RooSimultaneous *>(mc->GetPdf());

   for (std::size_t index_toy = 1; index_toy < 500; index_toy++) {

      const RooArgSet *Observables = (RooArgSet *)mc->GetObservables();
      std::vector<std::unique_ptr<RooDataSet>> toyDatas;
      std::map<string, RooDataSet *> toyDataMap;

      RooCategory channellist{"channellist", "channellist"};

      // generate each category
      for (auto const &item : pdf->indexCat()) {
         channellist.defineType(item.first.c_str());
         RooAbsPdf *pdftmp = pdf->getPdf(item.first.c_str());

         RooArgSet obstmp;
         pdftmp->getObservables(Observables, obstmp);

         toyDatas.emplace_back(static_cast<RooDataSet *>(pdftmp->generate(obstmp, Extended())));
         toyDataMap[item.first.c_str()] = toyDatas.back().get();
      }

      RooRealVar wt("wt", "wt", 1);
      RooDataSet toyData{"toyData", "", {*Observables, wt}, Index(channellist), Import(toyDataMap), WeightVar(wt)};

      if (index_toy % 10 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB << "   " << procinfo.fMemVirtual * toMB
                   << std::endl;
      }
   }
}

The output is now:

10: 346.156   441.535
20: 346.156   441.715
30: 346.156   441.715
40: 346.473   441.91
50: 346.473   441.91
60: 346.473   441.91
70: 346.73   442.301
80: 346.73   442.301
90: 346.73   442.301
100: 346.746   442.301
110: 346.746   442.301
120: 346.746   442.301
130: 346.746   442.301
140: 347.512   443.082
150: 347.512   443.082
160: 347.512   443.082
170: 347.512   443.082
180: 347.512   443.082
190: 347.512   443.082
200: 347.512   443.082
210: 347.512   443.082
220: 347.512   443.082
230: 347.512   443.082
240: 347.512   443.082
250: 347.512   443.082
260: 347.512   443.082
270: 347.512   443.082
280: 349.082   444.645
290: 349.082   444.645
300: 349.082   444.645
310: 349.082   444.645
320: 349.082   444.645
330: 349.082   444.645
340: 349.082   444.645
350: 349.082   444.645
360: 349.082   444.645
...

I will continue debugging this, starting from there.

@marcescalier
Copy link
Author

Thank you Jonas.
In my feeling this part of log proves somehow that memory is not freed at least for the first toy (index toy = 1) :

just before generate
res memory=314.93 Mbytes
vir memory=402.078 Mbytes
just after generate
res memory=334.656 Mbytes
vir memory=423.648 Mbytes

We see that after generate, the memory has increased (which is normal), but afterwards, even when deleting the generated dataset, we no more get back to the level of memory memory that was before the generate, even though we delete the generated dataset.

@guitargeek
Copy link
Contributor

guitargeek commented Jan 18, 2023

Yes yes I see the point for the first toy, but for the others I just didn't understand it.

Anyhow I'm convinced that there is a problem, and just to record my progress for today, here is a standalone reproducer that doesn't depend on Marcs workspace:

#include <RooGenContext.h>
#include <RooRealVar.h>
#include <RooExponential.h>
#include <RooUniform.h>
#include <RooMsgService.h>

#include <TFile.h>
#include <TSystem.h>

#include <iostream>

void repro()
{
   using namespace RooFit;

   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   RooRealVar x{"x", "x", 0.1, 5.1};
   RooRealVar c{"c", "c", -1.8, -5, 5};

   RooExponential expo{"expo", "expo", x, c};
   RooAbsPdf *pdf = &expo;

   // With the uniform distribution, there is no leak!
   // RooUniform uni{"uni", "uni", x};
   // RooAbsPdf * pdf = &uni;

   std::size_t nToys = 5000;

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB << "   " << procinfo.fMemVirtual * toMB
                   << std::endl;
      }

      if (index_toy == nToys) {
         RooMsgService::instance().addStream(DEBUG, Topic(Generation));
      }

      RooGenContext{*pdf, x};
   }
}

The output:

500: 209.504   345.379
1000: 209.762   345.77
1500: 209.762   345.77
2000: 210.535   346.551
2500: 210.535   346.551
3000: 210.535   346.551
3500: 210.535   346.551
4000: 212.082   348.117
4500: 212.082   348.117
5000: 212.082   348.117
[#3] INFO:Generation -- RooGenContext::ctor() setting up event generator context for p.d.f. expo for generation of observable(s) (x)
[#3] DEBUG:Generation -- RooGenContext::ctor() observables (x) are safe for internal generator (if supported by p.d.f)
[#3] DEBUG:Generation -- RooGenContext::ctor() Model indicates that it can internally generate observables () with configuration identifier 0
[#3] INFO:Generation -- RooGenContext::ctor() Context will generate variables (x) with accept/reject sampling
[#3] INFO:Generation -- RooGenContext::ctor() accept/reject sampling function is expo_AccRej
[#3] DEBUG:Generation -- RooGenContext::ctor() creating MC sampling generator RooFoamGenerator  from function for observables (x)

@guitargeek
Copy link
Contributor

I also increased the priority, because having a leak in such a fundamental operation with RooFit is not so great...

@marcescalier
Copy link
Author

Thanks a lot Jonas for your investigation, and for realizing that there is really something.

guitargeek added a commit to guitargeek/root that referenced this issue Jan 19, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.

Ater the last commit that excludes the TFoam classes from IO, this
commit is not a problem to the funcitonality because TFoam can't do IO
anyway, and no persistent reference with `TRef` are needed.
guitargeek added a commit to guitargeek/root that referenced this issue Jan 19, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.

Ater the last commit that excludes the TFoam classes from IO, this
commit is not a problem to the funcitonality because TFoam can't do IO
anyway, and no persistent reference with `TRef` are needed.
guitargeek added a commit to guitargeek/root that referenced this issue Jan 19, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.

After the last commit that excludes the TFoam classes from IO, this
commit is not a problem to the funcitonality because TFoam can't do IO
anyway, and no persistent reference with `TRef` are needed.
@guitargeek guitargeek linked a pull request Jan 19, 2023 that will close this issue
guitargeek added a commit to guitargeek/root that referenced this issue Jan 19, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.
guitargeek added a commit to guitargeek/root that referenced this issue Jan 19, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.
guitargeek added a commit to guitargeek/root that referenced this issue Jan 19, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.
guitargeek added a commit to guitargeek/root that referenced this issue Jan 20, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.
guitargeek added a commit that referenced this issue Jan 20, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in #8984.
guitargeek added a commit to guitargeek/root that referenced this issue Jan 22, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.
guitargeek added a commit that referenced this issue Jan 22, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in #8984.
@marcescalier
Copy link
Author

Thank you @guitargeek . Would you know in which root version I can check that it works ?

@guitargeek guitargeek reopened this Jan 23, 2023
@guitargeek
Copy link
Contributor

In the 6.28.00 release that will be released in a week or so. Sorry I didn't mean to close the issue, GitHub did that automatically! I'll leave this open until you confirm that the leak is gone.

If you manage to source them correctly, you can also try it out with the ROOT nightly builds:
https://root.cern/install/nightlies/

@guitargeek guitargeek removed this from the 6.28/00 milestone Jan 26, 2023
@guitargeek
Copy link
Contributor

Removing the 6.28 milestone because it should be already fixed in ROOT 6.28. This issue is only left open because the validation of the fix is still pending

@marcescalier
Copy link
Author

Thanks. I will test it in a few days. Apologizes for the delay.

@marcescalier
Copy link
Author

So unfortunately, I have no way to check with the nightly (apart if I would change/redevelop a new program).

The reason is that the workspace used in my example includes RooTwoSidedCBShape, which is unknown to root, so one needs to switch on first a tool that allows to access to RooTwoSidedCBShape. Such tools are not available with recent root versions.
So I just trust that it works but can't check. If so, maybe you may put as "resolved".

With root 6.29.01, this gives :

[escalier@lxplus745 /afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory] root -b -q "Minimum.C+()" |tee log_6.29.01

| Welcome to ROOT 6.29/01 https://root.cern |
| (c) 1995-2022, The ROOT Team; conception: R. Brun, F. Rademakers |
| Built for linuxx8664gcc on Jan 27 2023, 00:37:00 |
| From heads/master@v6-29-01-357-g4ef94f4 |
| With g++ (GCC) 11.3.0 |
| Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q' |

Processing Minimum.C+()...
Info in TUnixSystem::ACLiC: creating shared library /afs/cern.ch/work/e/escalier/public/ForOthers/ProblemMemory/./Minimum_C.so

Survey Memory, beginning of program
res memory=481.965 Mbytes
vir memory=760.32 Mbytes
Warning in TClass::Init: no dictionary for class RooTwoSidedCBShape is available
Survey Memory, after open file
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
Error in TBufferFile::ReadObject: trying to read an emulated class (RooTwoSidedCBShape) to store in a compiled pointer (TObject)
*** Error in `/cvmfs/sft-nightlies.cern.ch/lcg/nightlies/dev3/Fri/ROOT/HEAD/x86_64-centos7-gcc11-opt/bin/root.exe': free(): invalid pointer: 0x00007f1e9976b218 ***
======= Backtrace: =========

omazapa pushed a commit to omazapa/root that referenced this issue Apr 13, 2023
This fixes a memory leak related to the usage of `TRef` in `TFoamCell`
that can be reproduced with the following code:

```C++
class MyTFoamBinding : public TFoamIntegrand {
public:
   double Density(Int_t ndim, double *) override { return 1.0; }
};

void reproTFoam()
{
   ProcInfo_t procinfo;
   const float toMB = 1.f / 1024.f;

   std::size_t nToys = 5000;

   TRandom3 rand{};

   for (std::size_t index_toy = 1; index_toy <= nToys; index_toy++) {

      if (index_toy % 500 == 0) {
         gSystem->GetProcInfo(&procinfo);
         std::cout << index_toy << ": " << procinfo.fMemResident * toMB
                   << "   " << procinfo.fMemVirtual * toMB << std::endl;
      }

      MyTFoamBinding binding{};
      TFoam tfoam{"TFOAM"};
      tfoam.SetkDim(1);
      tfoam.SetRho(&binding);
      tfoam.SetPseRan(&rand);

      tfoam.SetnCells(30);

      tfoam.SetnSampl(200);
      tfoam.SetPseRan(&rand);
      tfoam.SetChat(0);
      tfoam.Initialize();
   }
}
```

Before this commit, you will see a steady memory increase that is gone
after this commit.

This fixes the fundamental memory increase in RooFit toy studies,
reported for example in root-project#8984.
@guitargeek
Copy link
Contributor

Okay, then I close this issue now! Feel free to open a new one if you see problems again.

@github-actions
Copy link

Hi @guitargeek,

It appears this issue is closed, but wasn't yet added to a project. Please add upcoming versions that will include the fix, or 'not applicable' otherwise.

Sincerely,
🤖

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants