Skip to content

Commit b9235ef

Browse files
committed
core: Add semantic ROOT::EnableImplicitMT (#18694)
Instead of specificy the number of core, the new overload can be specified to select a configuration type. Currently the following 2 configuration are supported: ROOT::EIMTConfig::kWholeMachine ROOT::EIMTConfig::kExistingTBBArena calling ``` ROOT::EnableImplicitMT(ROOT::EIMTConfig::kExistingTBBArena); ``` will attach to an existing TBB Arena instead of creating a new one. (cherry picked from commit eb0b903)
1 parent 94c1594 commit b9235ef

File tree

8 files changed

+127
-5
lines changed

8 files changed

+127
-5
lines changed

core/base/inc/TROOT.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,20 @@ namespace Internal {
8080
} } // End ROOT::Internal
8181

8282
namespace ROOT {
83+
enum class EIMTConfig {
84+
kWholeMachine = 0, ///< Default configuration
85+
kExistingTBBArena = 1, ///< Use the existing TBB arena
86+
kNumConfigs = 2 ///< Number of support IMT semantic configurations
87+
};
8388
/// \brief Enable support for multi-threading within the ROOT code
8489
/// in particular, enables the global mutex to make ROOT thread safe/aware.
8590
void EnableThreadSafety();
8691
/// \brief Enable ROOT's implicit multi-threading for all objects and methods that provide an internal
8792
/// parallelisation mechanism.
8893
void EnableImplicitMT(UInt_t numthreads = 0);
94+
/// \brief Enable ROOT's implicit multi-threading for all objects and methods that provide an internal
95+
/// parallelisation mechanism.
96+
void EnableImplicitMT(ROOT::EIMTConfig config);
8997
void DisableImplicitMT();
9098
Bool_t IsImplicitMTEnabled();
9199
UInt_t GetThreadPoolSize();

core/base/src/TROOT.cxx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,31 @@ namespace Internal {
551551
#endif
552552
}
553553

554+
////////////////////////////////////////////////////////////////////////////////
555+
/// @param[in] config Configuration to use. The default is kWholeMachine, which
556+
/// will create a thread pool that spans the whole machine.
557+
///
558+
/// EnableImplicitMT calls in turn EnableThreadSafety.
559+
/// If ImplicitMT is already enabled, this function does nothing.
560+
561+
void EnableImplicitMT(ROOT::EIMTConfig config)
562+
{
563+
#ifdef R__USE_IMT
564+
if (ROOT::Internal::IsImplicitMTEnabledImpl())
565+
return;
566+
EnableThreadSafety();
567+
static void (*sym)(ROOT::EIMTConfig) =
568+
(void (*)(ROOT::EIMTConfig))Internal::GetSymInLibImt("ROOT_TImplicitMT_EnableImplicitMT_Config");
569+
if (sym)
570+
sym(config);
571+
ROOT::Internal::IsImplicitMTEnabledImpl() = true;
572+
#else
573+
::Warning("EnableImplicitMT",
574+
"Cannot enable implicit multi-threading with config %d, please build ROOT with -Dimt=ON",
575+
static_cast<int>(config));
576+
#endif
577+
}
578+
554579
////////////////////////////////////////////////////////////////////////////////
555580
/// Disables the implicit multi-threading in ROOT (see EnableImplicitMT).
556581
void DisableImplicitMT()

core/imt/inc/ROOT/RTaskArena.hxx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#define ROOT_RTaskArena
2525

2626
#include "RConfigure.h"
27+
#include "TROOT.h" // For ROOT::EIMTConfig
2728
#include <memory>
2829

2930
// exclude in case ROOT does not have IMT support
@@ -65,9 +66,13 @@ public:
6566
~RTaskArenaWrapper(); // necessary to set size back to zero
6667
static unsigned TaskArenaSize(); // A static getter lets us check for RTaskArenaWrapper's existence
6768
ROOT::ROpaqueTaskArena &Access();
68-
private:
69+
struct Attach {}; ///< Marker for attaching to an existing tbb::task_arena
70+
6971
RTaskArenaWrapper(unsigned maxConcurrency = 0);
70-
friend std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned maxConcurrency);
72+
RTaskArenaWrapper(Attach);
73+
74+
private:
75+
friend std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned, ROOT::EIMTConfig);
7176
std::unique_ptr<ROOT::ROpaqueTaskArena> fTBBArena;
7277
static unsigned fNWorkers;
7378
};
@@ -81,6 +86,7 @@ private:
8186
/// references to the previous one are gone and the object destroyed.
8287
////////////////////////////////////////////////////////////////////////////////
8388
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned maxConcurrency = 0);
89+
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(ROOT::EIMTConfig config);
8490

8591
} // namespace Internal
8692
} // namespace ROOT

core/imt/src/ROpaqueTaskArena.hxx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#include "tbb/task_arena.h"
22

33
namespace ROOT {
4-
class ROpaqueTaskArena: public tbb::task_arena {};
4+
class ROpaqueTaskArena : public tbb::task_arena {
5+
public:
6+
using tbb::task_arena::task_arena;
7+
};
58
}

core/imt/src/RTaskArena.cxx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,20 @@ RTaskArenaWrapper::RTaskArenaWrapper(unsigned maxConcurrency) : fTBBArena(new RO
108108
ROOT::EnableThreadSafety();
109109
}
110110

111+
////////////////////////////////////////////////////////////////////////////////
112+
/// Initializes the tbb::task_arena within RTaskArenaWrapper by attaching to an
113+
/// existing arena.
114+
///
115+
/// * Can't be reinitialized
116+
////////////////////////////////////////////////////////////////////////////////
117+
RTaskArenaWrapper::RTaskArenaWrapper(RTaskArenaWrapper::Attach)
118+
: fTBBArena(new ROpaqueTaskArena{tbb::task_arena::attach{}})
119+
{
120+
fTBBArena->initialize(tbb::task_arena::attach{});
121+
fNWorkers = fTBBArena->max_concurrency();
122+
ROOT::EnableThreadSafety();
123+
}
124+
111125
RTaskArenaWrapper::~RTaskArenaWrapper()
112126
{
113127
fNWorkers = 0u;
@@ -127,7 +141,8 @@ ROOT::ROpaqueTaskArena &RTaskArenaWrapper::Access()
127141
return *fTBBArena;
128142
}
129143

130-
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned maxConcurrency)
144+
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper>
145+
GetGlobalTaskArena(unsigned maxConcurrency, ROOT::EIMTConfig config)
131146
{
132147
static std::weak_ptr<ROOT::Internal::RTaskArenaWrapper> weak_GTAWrapper;
133148

@@ -140,10 +155,31 @@ std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned m
140155
}
141156
return sp;
142157
}
143-
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> sp(new ROOT::Internal::RTaskArenaWrapper(maxConcurrency));
158+
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> sp;
159+
if (config == ROOT::EIMTConfig::kExistingTBBArena) {
160+
sp = std::make_shared<ROOT::Internal::RTaskArenaWrapper>(ROOT::Internal::RTaskArenaWrapper::Attach{});
161+
} else {
162+
if (config == ROOT::EIMTConfig::kWholeMachine) {
163+
maxConcurrency = 0;
164+
}
165+
sp = std::make_shared<ROOT::Internal::RTaskArenaWrapper>(maxConcurrency);
166+
}
144167
weak_GTAWrapper = sp;
145168
return sp;
146169
}
147170

171+
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(ROOT::EIMTConfig config)
172+
{
173+
if (config >= ROOT::EIMTConfig::kNumConfigs)
174+
::Fatal("ROOT::Internal::GetGlobalTaskArena",
175+
"Unsupported enum value %d", (int)config);
176+
return GetGlobalTaskArena(0, config);
177+
}
178+
179+
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned maxConcurrency)
180+
{
181+
return GetGlobalTaskArena(maxConcurrency, ROOT::EIMTConfig::kNumConfigs);
182+
}
183+
148184
} // namespace Internal
149185
} // namespace ROOT

core/imt/src/TImplicitMT.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// //
1919
//////////////////////////////////////////////////////////////////////////
2020

21+
#include "TROOT.h"
2122
#include "TError.h"
2223
#include "ROOT/RTaskArena.hxx"
2324
#include <atomic>
@@ -55,6 +56,22 @@ extern "C" void ROOT_TImplicitMT_EnableImplicitMT(UInt_t numthreads)
5556
}
5657
};
5758

59+
extern "C" void ROOT_TImplicitMT_EnableImplicitMT_Config(ROOT::EIMTConfig config)
60+
{
61+
if (!GetImplicitMTFlag()) {
62+
if (config < ROOT::EIMTConfig::kNumConfigs) {
63+
R__GetTaskArena4IMT() = ROOT::Internal::GetGlobalTaskArena(config);
64+
} else {
65+
::Warning("ROOT_TImplicitMT_EnableImplicitMT_Config",
66+
"Unknown enum value %d defaulting to EIMTCconfig::kWholeMachine", (int)config);
67+
R__GetTaskArena4IMT() = ROOT::Internal::GetGlobalTaskArena(0);
68+
}
69+
GetImplicitMTFlag() = true;
70+
} else {
71+
::Warning("ROOT_TImplicitMT_EnableImplicitMT_Config", "Implicit multi-threading is already enabled");
72+
}
73+
};
74+
5875
extern "C" void ROOT_TImplicitMT_DisableImplicitMT()
5976
{
6077
if (GetImplicitMTFlag()) {

core/imt/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66

77
ROOT_ADD_GTEST(testTaskArena testRTaskArena.cxx LIBRARIES Imt ${TBB_LIBRARIES} FAILREGEX "")
88
ROOT_ADD_GTEST(testTBBGlobalControl testTBBGlobalControl.cxx LIBRARIES Imt ${TBB_LIBRARIES})
9+
ROOT_ADD_GTEST(testEnableImt testEnableImt.cxx LIBRARIES Imt ${TBB_LIBRARIES})

core/imt/test/testEnableImt.cxx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include "TROOT.h"
2+
#include "ROOT/RTaskArena.hxx"
3+
4+
#include "tbb/task_arena.h"
5+
6+
#include "ROOT/TestSupport.hxx"
7+
#include "gtest/gtest.h"
8+
9+
#ifdef R__USE_IMT
10+
11+
static const unsigned gMaxConcurrency = ROOT::Internal::LogicalCPUBandwidthControl();
12+
13+
TEST(EnableImt, TBBAttach)
14+
{
15+
tbb::task_arena main_arena{2};
16+
17+
main_arena.execute([&]() { ROOT::EnableImplicitMT(ROOT::EIMTConfig::kExistingTBBArena); });
18+
19+
auto psize = ROOT::GetThreadPoolSize();
20+
21+
EXPECT_TRUE(psize > 1);
22+
EXPECT_EQ(main_arena.max_concurrency(), 2);
23+
EXPECT_EQ(psize, 2);
24+
}
25+
26+
#endif

0 commit comments

Comments
 (0)