Skip to content

Commit d1c610e

Browse files
committed
core: Add semantic ROOT::EnableImplicitMT
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. This fixes #18301
1 parent 7fe8ed5 commit d1c610e

File tree

8 files changed

+123
-6
lines changed

8 files changed

+123
-6
lines changed

core/base/inc/TROOT.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,21 @@ 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+
88+
};
8389
/// \brief Enable support for multi-threading within the ROOT code
8490
/// in particular, enables the global mutex to make ROOT thread safe/aware.
8591
void EnableThreadSafety();
8692
/// \brief Enable ROOT's implicit multi-threading for all objects and methods that provide an internal
8793
/// parallelisation mechanism.
8894
void EnableImplicitMT(UInt_t numthreads = 0);
95+
/// \brief Enable ROOT's implicit multi-threading for all objects and methods that provide an internal
96+
/// parallelisation mechanism.
97+
void EnableImplicitMT(ROOT::EIMTConfig config);
8998
void DisableImplicitMT();
9099
Bool_t IsImplicitMTEnabled();
91100
UInt_t GetThreadPoolSize();

core/base/src/TROOT.cxx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,29 @@ 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+
562+
void EnableImplicitMT(ROOT::EIMTConfig config)
563+
{
564+
#ifdef R__USE_IMT
565+
if (ROOT::Internal::IsImplicitMTEnabledImpl())
566+
return;
567+
EnableThreadSafety();
568+
static void (*sym)(ROOT::EIMTConfig) = (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", "Cannot enable implicit multi-threading with %d threads, please build ROOT with -Dimt=ON", numthreads);
574+
#endif
575+
}
576+
554577
////////////////////////////////////////////////////////////////////////////////
555578
/// Disables the implicit multi-threading in ROOT (see EnableImplicitMT).
556579
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+
private:
74+
75+
friend std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(bool, 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: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,21 @@ RTaskArenaWrapper::RTaskArenaWrapper(unsigned maxConcurrency) : fTBBArena(new RO
108108
ROOT::EnableThreadSafety();
109109
}
110110

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

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

@@ -140,10 +155,28 @@ 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 (semantic && config == ROOT::EIMTConfig::kExistingTBBArena) {
160+
sp = std::make_shared<ROOT::Internal::RTaskArenaWrapper>(ROOT::Internal::RTaskArenaWrapper::Attach{});
161+
} else {
162+
if (semantic && 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+
return GetGlobalTaskArena(true, 0, config);
174+
}
175+
176+
std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> GetGlobalTaskArena(unsigned maxConcurrency)
177+
{
178+
return GetGlobalTaskArena(false, maxConcurrency, ROOT::EIMTConfig::kNumConfigs);
179+
}
180+
148181
} // namespace Internal
149182
} // namespace ROOT

core/imt/src/TImplicitMT.cxx

Lines changed: 16 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,21 @@ 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", "Unknown enum value %d defaulting to EIMTCconfig::kWholeMachine", (int)config);
66+
R__GetTaskArena4IMT() = ROOT::Internal::GetGlobalTaskArena(0);
67+
}
68+
GetImplicitMTFlag() = true;
69+
} else {
70+
::Warning("ROOT_TImplicitMT_EnableImplicitMT_Config", "Implicit multi-threading is already enabled");
71+
}
72+
};
73+
5874
extern "C" void ROOT_TImplicitMT_DisableImplicitMT()
5975
{
6076
if (GetImplicitMTFlag()) {

core/imt/test/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
# For the list of contributors see $ROOTSYS/README/CREDITS.
66

77
ROOT_ADD_GTEST(testTaskArena testRTaskArena.cxx LIBRARIES Imt ${TBB_LIBRARIES} FAILREGEX "")
8-
ROOT_ADD_GTEST(testTBBGlobalControl testTBBGlobalControl.cxx LIBRARIES Imt ${TBB_LIBRARIES})
8+
ROOT_ADD_GTEST(testTBBGlobalControl testTBBGlobalControl.cxx testEnableImt.cxx LIBRARIES Imt ${TBB_LIBRARIES})
9+
ROOT_ADD_GTEST(testEnable 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;
16+
main_arena.initialize(2);
17+
18+
ROOT::EnableImplicitMT(ROOT::EIMTConfig::kExistingTBBArena);
19+
20+
auto psize = ROOT::GetThreadPoolSize();
21+
22+
EXPECT_TRUE( psize > 1);
23+
EXPECT_EQ( psize, 2); // gMaxConcurrency);
24+
}
25+
26+
#endif

0 commit comments

Comments
 (0)