diff --git a/core/base/inc/TROOT.h b/core/base/inc/TROOT.h index db22582c668cd..4ae127619837e 100644 --- a/core/base/inc/TROOT.h +++ b/core/base/inc/TROOT.h @@ -101,6 +101,7 @@ namespace ROOT { void EnableObjectAutoRegistration(); void DisableObjectAutoRegistration(); bool ObjectAutoRegistrationEnabled(); + void SetObjectAutoRegistrationDefault(bool enabled); } // namespace Experimental } diff --git a/core/base/src/TROOT.cxx b/core/base/src/TROOT.cxx index 9ee7e332ca2b3..0b96b4e065372 100644 --- a/core/base/src/TROOT.cxx +++ b/core/base/src/TROOT.cxx @@ -295,24 +295,29 @@ namespace { return moduleHeaderInfoBuffer; } + /// State helper for object auto registration. enum class AutoReg : unsigned char { kNotInitialised = 0, kOn, kOff, }; - //////////////////////////////////////////////////////////////////////////////// - /// \brief Test if various objects (such as TH1-derived classes) should automatically register - /// themselves (ROOT 6 mode) or not (ROOT 7 mode). - /// A default can be set in a .rootrc using e.g. "Root.ObjectAutoRegistration: 1" or setting - /// the environment variable "ROOT_OBJECT_AUTO_REGISTRATION=0". - AutoReg &ObjectAutoRegistrationEnabledImpl() + /// Set or read the default state for object auto registration. This state is used to initialise the + /// auto-registration state for each thread that starts. + AutoReg ObjectAutoRegistrationDefault(AutoReg defaultState) { static constexpr auto rcName = "Root.ObjectAutoRegistration"; // Update the docs if this is changed static constexpr auto envName = "ROOT_OBJECT_AUTO_REGISTRATION"; // Update the docs if this is changed - thread_local static AutoReg tlsState = AutoReg::kNotInitialised; + static std::atomic defaultFromAPI = AutoReg::kNotInitialised; - static const AutoReg defaultState = []() { + if (defaultState != AutoReg::kNotInitialised) { + defaultFromAPI = defaultState; + } + if (const auto apiDefault = defaultFromAPI.load(); apiDefault != AutoReg::kNotInitialised) { + return apiDefault; + } + + static const AutoReg defaultFromEnvironment = []() { AutoReg autoReg = AutoReg::kOn; // ROOT 6 default std::stringstream infoMessage; @@ -356,10 +361,18 @@ namespace { return autoReg; }(); - if (tlsState == AutoReg::kNotInitialised) { - assert(defaultState != AutoReg::kNotInitialised); - tlsState = defaultState; - } + return defaultFromEnvironment; + } + + //////////////////////////////////////////////////////////////////////////////// + /// \brief Test if various objects (such as TH1-derived classes) should automatically register + /// themselves (ROOT 6 mode) or not (ROOT 7 mode). + /// A default can be set in a .rootrc using e.g. "Root.ObjectAutoRegistration: 1" or setting + /// the environment variable "ROOT_OBJECT_AUTO_REGISTRATION=0". + AutoReg &ObjectAutoRegistrationEnabledImpl() + { + thread_local static AutoReg tlsState = ObjectAutoRegistrationDefault(AutoReg::kNotInitialised); + assert(tlsState != AutoReg::kNotInitialised); return tlsState; } @@ -733,10 +746,14 @@ namespace Internal { /// /// ## Setting defaults /// - /// A default can be set in a .rootrc using e.g. `Root.ObjectAutoRegistration: 1` or setting - /// the environment variable `ROOT_OBJECT_AUTO_REGISTRATION=0`. Note that this default affects - /// all the threads that get started. - /// When a default is set using one of these methods, ROOT will notify with an Info message. + /// A default can be set (in order of precedence): + /// 1. Using \ref SetObjectAutoRegistrationDefault(). + /// 2. Setting the environment variable `ROOT_OBJECT_AUTO_REGISTRATION=[01]` + /// 3. Setting `Root.ObjectAutoRegistration: [01]` in a .rootrc file. + /// + /// Note that this default affects all the threads that get started, but a running thread's behaviour + /// can only be changed using Enable/DisableObjectAutoRegistration(). + /// When the default state is changed using the environment or .rootrc, ROOT issues a reminder. /// /// ## Difference to TH1::AddDirectoryStatus() /// @@ -765,6 +782,16 @@ namespace Internal { assert(state != AutoReg::kNotInitialised); return state == AutoReg::kOn; } + + //////////////////////////////////////////////////////////////////////////////// + /// Set default for object auto registration when a thread starts up. + /// Threads that are already running are *not* affected by this call, including + /// the calling thread. + /// \copydetails ROOT::Experimental::EnableObjectAutoRegistration() + void SetObjectAutoRegistrationDefault(bool enabled) + { + ObjectAutoRegistrationDefault(enabled ? AutoReg::kOn : AutoReg::kOff); + } } // namespace Experimental } // end of ROOT namespace diff --git a/core/base/test/TROOTTests.cxx b/core/base/test/TROOTTests.cxx index a1ccc0ad87fb9..1aa1239454f29 100644 --- a/core/base/test/TROOTTests.cxx +++ b/core/base/test/TROOTTests.cxx @@ -87,7 +87,26 @@ TEST(TROOT, AutoRegistrationTLS) EnableObjectAutoRegistration(); EXPECT_EQ(ObjectAutoRegistrationEnabled(), true); - for (auto thread : {&t1, &t2, &t3, &t4}) { + const bool stateBeforeJoin = ObjectAutoRegistrationEnabled(); + + for (auto *thread : {&t1, &t2, &t3, &t4}) { thread->join(); } + + auto testAPIDefault = [](bool expectedState){ + EXPECT_EQ(ObjectAutoRegistrationEnabled(), expectedState); + }; + SetObjectAutoRegistrationDefault(true); + std::thread t5{testAPIDefault, true}; + + EXPECT_EQ(ObjectAutoRegistrationEnabled(), stateBeforeJoin); + + t5.join(); + + SetObjectAutoRegistrationDefault(false); + std::thread t6{testAPIDefault, false}; + + EXPECT_EQ(ObjectAutoRegistrationEnabled(), stateBeforeJoin); + + t6.join(); } diff --git a/math/mlp/inc/TMultiLayerPerceptron.h b/math/mlp/inc/TMultiLayerPerceptron.h index 36d5d01d34aab..1c423321091da 100644 --- a/math/mlp/inc/TMultiLayerPerceptron.h +++ b/math/mlp/inc/TMultiLayerPerceptron.h @@ -15,8 +15,8 @@ #include "TObject.h" #include "TString.h" #include "TObjArray.h" -#include "TMatrixD.h" #include "TNeuron.h" +#include "TMatrixDfwd.h" class TTree; class TEventList; diff --git a/math/mlp/src/TMLPAnalyzer.cxx b/math/mlp/src/TMLPAnalyzer.cxx index 39271c1e00c7f..afe7851f69062 100644 --- a/math/mlp/src/TMLPAnalyzer.cxx +++ b/math/mlp/src/TMLPAnalyzer.cxx @@ -350,6 +350,8 @@ void TMLPAnalyzer::DrawNetwork(Int_t neuron, const char* signal, const char* bg) // build event lists for signal and background TEventList* signal_list = new TEventList("__tmpSig_MLPA"); TEventList* bg_list = new TEventList("__tmpBkg_MLPA"); + signal_list->SetDirectory(gDirectory); + bg_list->SetDirectory(gDirectory); data->Draw(">>__tmpSig_MLPA",signal,"goff"); data->Draw(">>__tmpBkg_MLPA",bg,"goff"); diff --git a/math/mlp/src/TMultiLayerPerceptron.cxx b/math/mlp/src/TMultiLayerPerceptron.cxx index 87a6068a1c348..24309428c5179 100644 --- a/math/mlp/src/TMultiLayerPerceptron.cxx +++ b/math/mlp/src/TMultiLayerPerceptron.cxx @@ -242,6 +242,7 @@ neurons, hidden layers and inputs/outputs that does not apply to TMultiLayerPerc #include "TH2.h" #include "TGraph.h" #include "TLegend.h" +#include "TMatrixD.h" #include "TMultiGraph.h" #include "TDirectory.h" #include "TSystem.h" @@ -458,12 +459,12 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, TTree * data, fCurrentTree = -1; fCurrentTreeWeight = 1; { - TDirectory::TContext ctxt; + TDirectory::TContext ctxt{nullptr}; fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this)); } fTrainingOwner = true; { - TDirectory::TContext ctxt; + TDirectory::TContext ctxt{nullptr}; fTest = new TEventList(Form("fTestList_%zu",(size_t)this)); } fTestOwner = true; @@ -478,8 +479,12 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, TTree * data, fManager = nullptr; if (data) { BuildNetwork(); + fTraining->SetDirectory(gDirectory); + fTest->SetDirectory(gDirectory); data->Draw(Form(">>fTrainingList_%zu",(size_t)this),training,"goff"); data->Draw(Form(">>fTestList_%zu",(size_t)this),(const char *)testcut,"goff"); + fTraining->SetDirectory(nullptr); + fTest->SetDirectory(nullptr); AttachData(); } else { @@ -537,12 +542,12 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, fCurrentTree = -1; fCurrentTreeWeight = 1; { - TDirectory::TContext ctxt; + TDirectory::TContext ctxt{nullptr}; fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this)); } fTrainingOwner = true; { - TDirectory::TContext ctxt; + TDirectory::TContext ctxt{nullptr}; fTest = new TEventList(Form("fTestList_%zu",(size_t)this)); } fTestOwner = true; @@ -557,8 +562,12 @@ TMultiLayerPerceptron::TMultiLayerPerceptron(const char * layout, fManager = nullptr; if (data) { BuildNetwork(); + fTraining->SetDirectory(gDirectory); + fTest->SetDirectory(gDirectory); data->Draw(Form(">>fTrainingList_%zu",(size_t)this),training,"goff"); data->Draw(Form(">>fTestList_%zu",(size_t)this),(const char *)testcut,"goff"); + fTraining->SetDirectory(nullptr); + fTest->SetDirectory(nullptr); AttachData(); } else { @@ -645,12 +654,14 @@ void TMultiLayerPerceptron::SetTrainingDataSet(const char * train) { if(fTraining && fTrainingOwner) delete fTraining; { - TDirectory::TContext ctxt; + TDirectory::TContext ctxt{nullptr}; fTraining = new TEventList(Form("fTrainingList_%zu",(size_t)this)); } fTrainingOwner = true; if (fData) { + fTraining->SetDirectory(gDirectory); fData->Draw(Form(">>fTrainingList_%zu",(size_t)this),train,"goff"); + fTraining->SetDirectory(nullptr); } else { Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets"); @@ -672,7 +683,9 @@ void TMultiLayerPerceptron::SetTestDataSet(const char * test) } fTestOwner = true; if (fData) { + fTraining->SetDirectory(gDirectory); fData->Draw(Form(">>fTestList_%zu",(size_t)this),test,"goff"); + fTraining->SetDirectory(nullptr); } else { Warning("TMultiLayerPerceptron::TMultiLayerPerceptron","Data not set. Cannot define datasets"); diff --git a/roottest/root/tree/cache/variableCluster.C b/roottest/root/tree/cache/variableCluster.C index a712392e5feb6..de107e8a40324 100644 --- a/roottest/root/tree/cache/variableCluster.C +++ b/roottest/root/tree/cache/variableCluster.C @@ -220,26 +220,13 @@ Long64_t checkBoundary(TTree *tree, Long64_t entry) TTree::TClusterIterator clusterIter = tree->GetClusterIterator(entry); fEntryCurrent = clusterIter(); fEntryNext = clusterIter.GetNextEntry(); - + // fprintf(stdout,"finds = %lld %lld\n",fEntryCurrent,fEntryNext); - + if (fEntryCurrent < fEntryMin) fEntryCurrent = fEntryMin; if (fEntryMax <= 0) fEntryMax = tree->GetEntries(); if (fEntryNext > fEntryMax) fEntryNext = fEntryMax; - - // Check if owner has a TEventList set. If yes we optimize for this - // Special case reading only the baskets containing entries in the - // list. -// TEventList *elist = fOwner->GetEventList(); -// Long64_t chainOffset = 0; -// if (elist) { -// if (fOwner->IsA() ==TChain::Class()) { -// TChain *chain = (TChain*)fOwner; -// Int_t t = chain->GetTreeNumber(); -// chainOffset = chain->GetTreeOffset()[t]; -// } -// } - + Int_t flushIntervals = 0; Long64_t minEntry = fEntryCurrent; Long64_t prevNtot; diff --git a/tmva/tmva/src/Classification.cxx b/tmva/tmva/src/Classification.cxx index 58b21238dc63a..8a8ec50f03280 100644 --- a/tmva/tmva/src/Classification.cxx +++ b/tmva/tmva/src/Classification.cxx @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/tmva/tmva/src/DataInputHandler.cxx b/tmva/tmva/src/DataInputHandler.cxx index bde79ed57e965..2c725b85aa03f 100644 --- a/tmva/tmva/src/DataInputHandler.cxx +++ b/tmva/tmva/src/DataInputHandler.cxx @@ -36,12 +36,9 @@ Class that contains all the data information. #include "TMVA/DataLoader.h" #include "TMVA/MsgLogger.h" #include "TMVA/Types.h" -#include "TEventList.h" #include "TCut.h" #include "TTree.h" -#include "TMVA/Configurable.h" - #include #include diff --git a/tmva/tmva/src/DataSetFactory.cxx b/tmva/tmva/src/DataSetFactory.cxx index 8b09d1bb9eb14..96d9b2e85d334 100644 --- a/tmva/tmva/src/DataSetFactory.cxx +++ b/tmva/tmva/src/DataSetFactory.cxx @@ -41,26 +41,17 @@ Class that contains all the data information #include #include -#include -#include -#include #include "TMVA/DataSetFactory.h" -#include "TEventList.h" #include "TFile.h" #include "TRandom3.h" -#include "TMatrixF.h" -#include "TVectorF.h" #include "TMath.h" #include "TTree.h" #include "TBranch.h" #include "TMVA/MsgLogger.h" #include "TMVA/Configurable.h" -#include "TMVA/VariableIdentityTransform.h" -#include "TMVA/VariableDecorrTransform.h" -#include "TMVA/VariablePCATransform.h" #include "TMVA/DataSet.h" #include "TMVA/DataSetInfo.h" #include "TMVA/DataInputHandler.h" diff --git a/tmva/tmva/src/DataSetInfo.cxx b/tmva/tmva/src/DataSetInfo.cxx index 651f1e6b9b99d..6edf91cde5076 100644 --- a/tmva/tmva/src/DataSetInfo.cxx +++ b/tmva/tmva/src/DataSetInfo.cxx @@ -31,14 +31,8 @@ Class that contains all the data information. */ -#include - -#include "TEventList.h" #include "TH2.h" -#include "TRandom3.h" #include "TMatrixF.h" -#include "TVectorF.h" -#include "TROOT.h" #include "TMVA/MsgLogger.h" #include "TMVA/Tools.h" @@ -50,6 +44,8 @@ Class that contains all the data information. #include "TMVA/Types.h" #include "TMVA/VariableInfo.h" +#include + //////////////////////////////////////////////////////////////////////////////// /// constructor diff --git a/tmva/tmva/src/Factory.cxx b/tmva/tmva/src/Factory.cxx index 278730bbef214..42f3081621be6 100644 --- a/tmva/tmva/src/Factory.cxx +++ b/tmva/tmva/src/Factory.cxx @@ -71,26 +71,23 @@ evaluation phases. #include "TMVA/ResultsClassification.h" #include "TMVA/ResultsRegression.h" #include "TMVA/ResultsMulticlass.h" -#include -#include -#include #include "TMVA/Types.h" #include "TROOT.h" #include "TFile.h" -#include "TLeaf.h" -#include "TEventList.h" #include "TH2.h" #include "TGraph.h" #include "TStyle.h" -#include "TMatrixF.h" -#include "TMatrixDSym.h" -#include "TMultiGraph.h" #include "TPrincipal.h" #include "TMath.h" #include "TSystem.h" #include "TCanvas.h" +#include "TMultiGraph.h" + +#include +#include +#include const Int_t MinNoTrainingEvents = 10; // const Int_t MinNoTestEvents = 1; diff --git a/tmva/tmva/src/MethodTMlpANN.cxx b/tmva/tmva/src/MethodTMlpANN.cxx index f67da9507ba78..39b6b8abf2dad 100644 --- a/tmva/tmva/src/MethodTMlpANN.cxx +++ b/tmva/tmva/src/MethodTMlpANN.cxx @@ -46,7 +46,6 @@ for details on this ANN. #include "TMVA/MethodTMlpANN.h" #include "TMVA/Config.h" -#include "TMVA/Configurable.h" #include "TMVA/DataSet.h" #include "TMVA/DataSetInfo.h" #include "TMVA/IMethod.h" @@ -58,8 +57,6 @@ for details on this ANN. #include "TMVA/ClassifierFactory.h" #include "TMVA/Tools.h" -#include "TLeaf.h" -#include "TEventList.h" #include "TROOT.h" #include "TMultiLayerPerceptron.h" #include "ThreadLocalStorage.h" diff --git a/tree/tree/inc/TEventList.h b/tree/tree/inc/TEventList.h index cf2a7a616fa65..2bbc1fc85876c 100644 --- a/tree/tree/inc/TEventList.h +++ b/tree/tree/inc/TEventList.h @@ -31,15 +31,15 @@ class TCollection; class TEventList : public TNamed { protected: - Int_t fN; ///< Number of elements in the list - Int_t fSize; ///< Size of array - Int_t fDelta; ///< Increment size - bool fReapply; ///< If true, TTree::Draw will 'reapply' the original cut - Long64_t *fList; ///<[fN]Array of elements - TDirectory *fDirectory; /// 100) fSize = initsize; else fSize = 100; if (delta > 100) fDelta = delta; else fDelta = 100; fList = nullptr; - fDirectory = gDirectory; - if (fDirectory) fDirectory->Append(this); + if (ROOT::Experimental::ObjectAutoRegistrationEnabled()) { + fDirectory = gDirectory; + if (fDirectory) fDirectory->Append(this); + } } //////////////////////////////////////////////////////////////////////////////// @@ -107,9 +91,9 @@ TEventList::TEventList(const TEventList &list) : TNamed(list) TEventList::~TEventList() { - delete [] fList; fList = nullptr; - if (fDirectory) fDirectory->Remove(this); - fDirectory = nullptr; + delete[] fList; + if (fDirectory) + fDirectory->Remove(this); } //////////////////////////////////////////////////////////////////////////////// diff --git a/tree/treeplayer/src/TSelectorDraw.cxx b/tree/treeplayer/src/TSelectorDraw.cxx index 8aa71aec11512..01f09336ee59d 100644 --- a/tree/treeplayer/src/TSelectorDraw.cxx +++ b/tree/treeplayer/src/TSelectorDraw.cxx @@ -410,6 +410,7 @@ void TSelectorDraw::Begin(TTree *tree) } else { enlist = new TEntryList(hname, realSelection.GetTitle()); } + enlist->SetDirectory(gDirectory); // TTree::Draw documentation promises it shows up in gDirectory } if (enlist) { if (!hnameplus) { @@ -421,6 +422,7 @@ void TSelectorDraw::Begin(TTree *tree) } else { inElist = new TEntryList(*enlist); } + inElist->SetDirectory(gDirectory); // TTree::Draw documentation promises it shows up in gDirectory fCleanElist = true; fTree->SetEntryList(inElist); } @@ -445,6 +447,7 @@ void TSelectorDraw::Begin(TTree *tree) } if (!evlist) { evlist = new TEventList(hname, realSelection.GetTitle(), 1000, 0); + evlist->SetDirectory(gDirectory); // TTree::Draw documentation promises it shows up in gDirectory } if (evlist) { if (!hnameplus) { diff --git a/tree/treeplayer/src/TTreePlayer.cxx b/tree/treeplayer/src/TTreePlayer.cxx index 4065337e4d956..6decc11d535fb 100644 --- a/tree/treeplayer/src/TTreePlayer.cxx +++ b/tree/treeplayer/src/TTreePlayer.cxx @@ -622,8 +622,6 @@ Long64_t TTreePlayer::GetEntriesToProcess(Long64_t firstentry, Long64_t nentries lastentry = fTree->GetEntriesFriend() - 1; nentries = lastentry - firstentry + 1; } - //TEventList *elist = fTree->GetEventList(); - //if (elist && elist->GetN() < nentries) nentries = elist->GetN(); TEntryList *elist = fTree->GetEntryList(); if (elist && elist->GetN() < nentries) nentries = elist->GetN(); return nentries; diff --git a/tree/treeviewer/src/TSpider.cxx b/tree/treeviewer/src/TSpider.cxx index 4b8bd6b06c7c9..205939bb3bd3d 100644 --- a/tree/treeviewer/src/TSpider.cxx +++ b/tree/treeviewer/src/TSpider.cxx @@ -730,8 +730,6 @@ Long64_t TSpider::GetEntriesToProcess(Long64_t firstentry, Long64_t nentries) co lastentry = fTree->GetEntriesFriend() - 1; nentries = lastentry - firstentry + 1; } - //TEventList *elist = fTree->GetEventList(); - //if (elist && elist->GetN() < nentries) nentries = elist->GetN(); TEntryList *elist = fTree->GetEntryList(); if (elist && elist->GetN() < nentries) nentries = elist->GetN(); return nentries;