St9bad_alloc when accessing ntuple variables

Hello,

I’m having a problem accessing ntuple variables (which are simply doubles/floats or arrays of doubles/floats) created by my otherwise relatively straightforward code (attached PlotVBF.cpp) which fills some histograms and an ntuple and stores them in a ROOT file.

If I try to Draw, Scan, or otherwise access the leaves stored in the ntuple (named nntree in the code) after a run, I get a segmentation fault, such as follows:

[code]root [1] TTree t=nntree
root [2] t->Scan(“Njet:invmass”)


  • Row * Njet * invmass *

terminate called after throwing an instance of ‘std::bad_alloc’
what(): St9bad_alloc[/code]

It is only the ntuple that is affected, the histograms plotted in the same file never suffer from any problems.
I first noticed this problem when trying to merge some root files created by parallel jobs, where I saw errors like:

Error in <TFile::ReadBuffer>: error reading all requested bytes ...
similar to what the poster in topic http://root.cern.ch/phpBB2/viewtopic.php?t=7547 saw.

Experimenting, I find that if my ntuple has less than around a couple thousand entries, I can access the variables with no problem, but any more than this causes the segmentation fault above (but obviously this is not a reasonable solution!).

I guess I’m doing something silly in the way I’m defining or filling these branches, but I’ve been puzzling over this for a few days now and can’t see where the problem lies, so I’d appreciate any help/suggestions you have!

Many thanks,
Darren
PlotVBF.cpp (62 KB)

root [1] TTree t=nntreeThis looks like an illegal statement (guessing that nntree is a pointer to a TTree coming from the file). Even if it was to somehow (older version of ROOT?) work it would be likely to only partially copy the TTree object (i.e. only copy the meta data but not the actual data). So a priori root [1] TTree * t=nntree; root [2] t->Scan("Njet:invmass");should work. If it does not work, this means that you are somehow detaching the TTree for the file (which would indeed seems to work if you have both an older version of ROOT and only a few entries). If you can avoid this detaching, this would solve your problem. If you must detach the tree from file, then you must load all the basket in memory (assuming you have enough RAM) via mytree->LoadBaskets();

Cheers,
Philippe.

Hi Philippe,

Thanks for your response, I am indeed accessing the TTree with

root [1] TTree * t=nntree; 

not “TTree t=nntree” (it seems a typo slipped in between copying from my terminal somehow), so this is not the source of my problem.

I’m not sure I understand what you mean about ‘detaching the TTree for the file’? In what way could I be doing this? The only code I have which does anything to the root file I have posted above, and as far as I know I am simply filling an ntuple, then writing it to file.

In any case, I tried issuing the LoadBaskets() command in ROOT after I loaded the TTree (I’m not sure if this is what you meant for me to do) and got the following error:

root [3] t->LoadBaskets() Error in <TFile::ReadBuffer>: error reading all requested bytes from file VBFPlot.root, got 0 of 3443

As the root files I have fro my test jobs are not so large, I have attached an example one from one of my jobs to this post, in case this helps shed light on the problem!

Thanks for your help,
Darren
VBFPlot.root (650 KB)

Hi,

Your file is mal-formed per se. The data for the TTree has seemingly been written to a different file!

I can not tell from your code into which file it was saved, but it is a file that was create slightly before the call to the TTree constructor (in your PlotVBF::begin).

You have two solution. You can make the TTree memory resident by calling just after the constructor: nntree->SetDirectory(0);
or better, you can make the TTree resident on your output file by moving the creation of the output file from PlotVBF::finish to PlotVBF::begin

Cheers,
Philippe.

Hi Philippe,

I re-organised my code so that the output file is created in begin() rather than finish() as you suggested, and this indeed seems to have fixed the problem! Thanks for your help with this!

[Interestingly, the root file I posted still does contain some meaningful (if incomplete) data (if you Scan(“Njet”) for example), and as I mentioned before this problem did not manifest itself for small numbers of entries. From your solution, I guess that what was happening in the setup I had originally was at time of the file creation, root was able to save whatever was in memory to the file, but lost some/most data if the number of entries got too large leading to the corrupted file. ]

Again, thanks for finding the solution to my problem!
Best regards,
Darren

[quote][Interestingly, the root file I posted still does contain some meaningful (if incomplete) data (if you Scan(“Njet”) for example), and as I mentioned before this problem did not manifest itself for small numbers of entries. From your solution, I guess that what was happening in the setup I had originally was at time of the file creation, root was able to save whatever was in memory to the file, but lost some/most data if the number of entries got too large leading to the corrupted file. ][/quote]This would have ‘worked’ only in version of ROOT earlier than 5.20. In those older version the ‘last’ buffer was always saved in the same key as the TTree object and hence if you have few events and hence only one buffer, it would seem to appear to work (as you have noticed). In v5.20, for (memory) performance reasons, the last buffers are now saved as any other buffer … and thus your old example would now always fails even with a small number of entries.

Cheers,
Philippe