-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[Root7] A path to reducing global object registration and management. #18083
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
base: master
Are you sure you want to change the base?
Changes from all commits
61e4aea
90bc619
3d46f84
80ff8c3
5650100
6e1c381
7edbb01
3b18ea1
e42b8ff
a9ae83c
d114ea5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -157,10 +157,11 @@ | |
| INCREMENTAL: ${{ !contains(github.event.pull_request.labels.*.name, 'clean build') && !matrix.platform == 'mac15' && !matrix.platform == 'mac26'}} | ||
| GITHUB_PR_ORIGIN: ${{ github.event.pull_request.head.repo.clone_url }} | ||
| OVERRIDES: ${{ join( matrix.overrides, ' ') }} | ||
| ROOT_OBJECT_AUTO_REGISTRATION: 0 | ||
| run: | | ||
|
Check failure on line 161 in .github/workflows/root-ci.yml
|
||
| [ -d "${VIRTUAL_ENV_DIR}" ] && source ${VIRTUAL_ENV_DIR}/bin/activate | ||
| echo "Python is now $(which python3) $(python3 --version)" | ||
| src/.github/workflows/root-ci-config/build_root.py \ | ||
| src/.github/workflows/root-ci-config/build_root.py \ | ||
| --buildtype RelWithDebInfo \ | ||
| --incremental $INCREMENTAL \ | ||
| --base_ref ${{ github.base_ref }} \ | ||
|
|
@@ -286,8 +287,9 @@ | |
| env: | ||
| INCREMENTAL: ${{ !contains(github.event.pull_request.labels.*.name, 'clean build') }} | ||
| GITHUB_PR_ORIGIN: ${{ github.event.pull_request.head.repo.clone_url }} | ||
| ROOT_OBJECT_AUTO_REGISTRATION: 0 | ||
| shell: cmd | ||
| run: "C:\\setenv.bat ${{ matrix.target_arch }} && | ||
|
Check failure on line 292 in .github/workflows/root-ci.yml
|
||
| python .github/workflows/root-ci-config/build_root.py | ||
| --buildtype ${{ matrix.config }} | ||
| --platform windows10 | ||
|
|
@@ -447,7 +449,7 @@ | |
| - self-hosted | ||
| - linux | ||
| - ${{ matrix.architecture == null && 'x64' || matrix.architecture }} | ||
| - ${{ matrix.extra-runs-on == null && 'cpu' || matrix.extra-runs-on }} | ||
|
Check failure on line 452 in .github/workflows/root-ci.yml
|
||
|
|
||
| name: | | ||
| ${{ matrix.image }} ${{ matrix.property }} | ||
|
|
@@ -512,7 +514,8 @@ | |
| INCREMENTAL: ${{ !contains(github.event.pull_request.labels.*.name, 'clean build') }} | ||
| GITHUB_PR_ORIGIN: ${{ github.event.pull_request.head.repo.clone_url }} | ||
| OVERRIDES: ${{ join( matrix.overrides, ' ') }} | ||
| ROOT_OBJECT_AUTO_REGISTRATION: 0 | ||
| run: ".github/workflows/root-ci-config/build_root.py | ||
|
Check failure on line 518 in .github/workflows/root-ci.yml
|
||
| --buildtype RelWithDebInfo | ||
| --platform ${{ matrix.image }} | ||
| --platform_config ${{ matrix.platform_config }} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -71,9 +71,11 @@ of a main program creating an interactive version is shown below: | |
| #include <ROOT/RVersion.hxx> | ||
| #include "RConfigure.h" | ||
| #include "RConfigOptions.h" | ||
| #include <atomic> | ||
| #include <filesystem> | ||
| #include <string> | ||
| #include <map> | ||
| #include <sstream> | ||
| #include <set> | ||
| #include <cstdlib> | ||
| #ifdef WIN32 | ||
|
|
@@ -298,6 +300,75 @@ namespace { | |
| static std::vector<ModuleHeaderInfo_t> moduleHeaderInfoBuffer; | ||
| return moduleHeaderInfoBuffer; | ||
| } | ||
|
|
||
| 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() | ||
| { | ||
| 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 const AutoReg defaultState = []() { | ||
| AutoReg autoReg = AutoReg::kOn; // ROOT 6 default | ||
| std::stringstream infoMessage; | ||
|
|
||
| if (gEnv) { | ||
| const auto desiredValue = gEnv->GetValue(rcName, -1); | ||
| if (desiredValue == 0) { | ||
| autoReg = AutoReg::kOff; | ||
| infoMessage << "disabled in " << gEnv->GetRcName(); | ||
| } else if (desiredValue == 1) { | ||
| autoReg = AutoReg::kOn; | ||
| infoMessage << "enabled in " << gEnv->GetRcName(); | ||
| } else if (desiredValue != -1) { | ||
| Error("TROOT", "%s should be 0 or 1", rcName); | ||
| } | ||
| } | ||
|
|
||
| if (const auto env = gSystem->Getenv(envName); env) { | ||
| int desiredValue = -1; | ||
| try { | ||
| desiredValue = std::stoi(env); | ||
| } catch (std::invalid_argument &e) { | ||
| Error("TROOT", "%s should be 0 or 1", envName); | ||
| } | ||
| if (desiredValue == 0) { | ||
| autoReg = AutoReg::kOff; | ||
| infoMessage << (infoMessage.str().empty() ? "" : " and ") << "disabled using the environment variable " | ||
| << envName; | ||
| } else if (desiredValue == 1) { | ||
| autoReg = AutoReg::kOn; | ||
| infoMessage << (infoMessage.str().empty() ? "" : " and ") << "enabled using the environment variable " | ||
| << envName; | ||
| } else { | ||
| Error("TROOT", "%s should be 0 or 1", envName); | ||
| } | ||
| } | ||
|
|
||
| if (!infoMessage.str().empty()) { | ||
| Info("TROOT", "Object auto registration %s\n", infoMessage.str().c_str()); | ||
| } | ||
|
|
||
| return autoReg; | ||
| }(); | ||
|
|
||
| if (tlsState == AutoReg::kNotInitialised) { | ||
| assert(defaultState != AutoReg::kNotInitialised); | ||
| tlsState = defaultState; | ||
| } | ||
|
|
||
| return tlsState; | ||
|
pcanal marked this conversation as resolved.
|
||
| } | ||
| } | ||
|
|
||
| Int_t TROOT::fgDirLevel = 0; | ||
|
|
@@ -475,7 +546,6 @@ namespace Internal { | |
| static Bool_t isImplicitMTEnabled = kFALSE; | ||
| return isImplicitMTEnabled; | ||
| } | ||
|
|
||
| } // end of Internal sub namespace | ||
| // back to ROOT namespace | ||
|
|
||
|
|
@@ -621,6 +691,87 @@ namespace Internal { | |
| return 0; | ||
| #endif | ||
| } | ||
|
|
||
| /// Namespace for ROOT features in testing. | ||
| /// The API might change without notice until moved out of this namespace. | ||
| namespace Experimental { | ||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// \brief Enable automatic registration of objects for the current thread (ROOT 6 default). | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry to be picky here: does it make sense to have a table of the classes the instances of which are affected by the switch in this documentation?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| /// | ||
| /// In ROOT 6 mode, ROOT will implicitly assign ownership of histograms or TTrees | ||
| /// to the current \ref gDirectory, for example to the last TFile that was opened. | ||
| /// \code{.cpp} | ||
| /// TFile file(...); | ||
| /// TTree* tree = new TTree(...); | ||
| /// TH1D* histo = new TH1D(...); | ||
| /// file.Write(); // Both tree and histogram are in the file now | ||
| /// \endcode | ||
| /// | ||
| /// On the path to ROOT 7, the auto registration of most objects will be phased out, so | ||
| /// they are fully owned by the user. To write these to files, the user needs to do | ||
| /// one of the following: | ||
| /// - Manage the object, and write it explicitly: | ||
| /// \code{.cpp} | ||
| /// TFile file(...); | ||
| /// std::unique_ptr<TH1D> histo{new TH1D(...)}; | ||
| /// file.WriteObject(histo.get(), "HistogramName"); | ||
| /// // histo remains valid even if the file is closed | ||
| /// \endcode | ||
| /// - Explicitly transfer ownership to the file using `SetDirectory()`: | ||
| /// \code{.cpp} | ||
| /// TFile file(...); | ||
| /// TH1x* histogram = new TH1x(...); | ||
| /// histogram->SetDirectory(&file); | ||
| /// \endcode | ||
| /// | ||
| /// ### Objects covered by this mode | ||
| /// | ||
| /// | | Honours `DisableObjectAutoRegistration()`? | Could this be disabled previously? | | ||
| /// | --------------------- | ------------------------------------------ | ---------------------------------- | | ||
| /// | TH1 and derived | Yes | TH1::AddDirectoryStatus() | | ||
| /// | TGraph2D | Yes | TH1::AddDirectoryStatus() | | ||
| /// | RooPlot | Yes | RooPlot::addDirectoryStatus() | | ||
| /// | TEfficiency | Yes | No | | ||
| /// | TProfile2D | Yes | TH1::AddDirectoryStatus() | | ||
| /// | TEntryList | No, but planned for 6.42 | No | | ||
| /// | TEventList | No, but planned for 6.42 | No | | ||
| /// | TFunction | No, but work in progress | No | | ||
| /// | ||
| /// ## 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. | ||
| /// | ||
| /// ## Difference to TH1::AddDirectoryStatus() | ||
| /// | ||
| /// For classes deriving from TH1, both ObjectAutoRegistrationEnabled() and TH1::AddDirectoryStatus() | ||
| /// need to be true for auto-registration to take effect. The former should be preferred over the latter, however, | ||
| /// because it is thread local and extends to more objects such as TGraph2D, TEfficiency, RooPlot. | ||
| void EnableObjectAutoRegistration() | ||
| { | ||
| ObjectAutoRegistrationEnabledImpl() = AutoReg::kOn; | ||
| } | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// \brief Disable automatic registration of objects for the current thread (ROOT 7 default). | ||
| /// \copydetails ROOT::Experimental::EnableObjectAutoRegistration() | ||
| void DisableObjectAutoRegistration() | ||
| { | ||
| ObjectAutoRegistrationEnabledImpl() = AutoReg::kOff; | ||
| } | ||
|
|
||
| //////////////////////////////////////////////////////////////////////////////// | ||
| /// Test whether objects in this thread auto-register themselves, e.g. to the current ROOT directory. | ||
| /// \copydetails ROOT::Experimental::EnableObjectAutoRegistration() | ||
| bool ObjectAutoRegistrationEnabled() | ||
| { | ||
| const auto state = ObjectAutoRegistrationEnabledImpl(); | ||
| assert(state != AutoReg::kNotInitialised); | ||
| return state == AutoReg::kOn; | ||
| } | ||
| } // namespace Experimental | ||
| } // end of ROOT namespace | ||
|
|
||
| TROOT *ROOT::Internal::gROOTLocal = ROOT::GetROOT(); | ||
|
|
||

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commit will be removed before merging. It is here to demonstrate that all tests work today also when object auto registration is off.