Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
Executor.h
Go to the documentation of this file.
1 // @(#)root/tmva $Id$
2 // Author: Lorenzo Moneta
3 /*************************************************************************
4  * Copyright (C) 2019, ROOT/TMVA *
5  * All rights reserved. *
6  * *
7  * For the licensing terms see $ROOTSYS/LICENSE. *
8  * For the list of contributors see $ROOTSYS/README/CREDITS. *
9  *************************************************************************/
10 
11 //////////////////////////////////////////////////////////////////////////
12 //
13 // Defining Executor classes to be used in TMVA
14 // wrapping the functionality of the ROOT TThreadExecutor and
15 // ROOT TSequential Executor
16 //
17 /////////////////////////////////////////////////////////////////////////
18 #ifndef ROOT_TMVA_Executor
19 #define ROOT_TMVA_Executor
20 
21 #include <memory>
22 
24 #ifdef R__USE_IMT
25 #include <ROOT/TThreadExecutor.hxx>
26 #endif
27 
28 #include <TROOT.h>
29 #include <TError.h>
30 
31 namespace TMVA {
32 
33 
34 /// Base Excutor class
35 class Executor {
36 
37 public:
38 
39  template< class F, class... T>
40  using noReferenceCond = typename std::enable_if<"Function can't return a reference" &&
41  !(std::is_reference<typename std::result_of<F(T...)>::type>::value)>::type;
42 
43 
44 
45  //////////////////////////////////////
46  /// Default constructor of TMVA Executor class
47  /// if ROOT::EnableIMplicitMT has not been called then by default a serial executor will be created
48  /// A user can create a thread pool and enable multi-thread excution by calling TMVA::Config::Instance()::EnableMT(nthreads)
49  /// For releasing the thread pool used by TMVA one can do it by calling TMVA::Config::Instance()::DisableMT() or
50  /// calling TMVA::Config::Instance()::EnableMT with only one thread
51  ////////////////////////////////////////////
52  Executor() {
53  // enable MT in TMVA if ROOT::IsImplicitMT is enabled
54  if (ROOT::IsImplicitMTEnabled() ) {
55 #ifdef R__USE_IMT
56  fMTExecImpl = std::unique_ptr< ROOT::TThreadExecutor>(new ROOT::TThreadExecutor());
57 #else
58  ::Error("Executor","Cannot have TMVA in multi-threads mode when ROOT is built without IMT");
59 #endif
60  }
61  // case of single thread usage
62  if (!fMTExecImpl)
63  fSeqExecImpl = std::unique_ptr<ROOT::TSequentialExecutor>(new ROOT::TSequentialExecutor());
64  }
65 
66  //////////////////////////////////////
67  /// Constructor of TMVA Executor class
68  /// Explicit specify the number of threads. In this case if nthreads is > 1 a multi-threaded executor will be created and
69  /// TMVA will run in MT.
70  /// If nthreads = 1 instead TMVA will run in sequential mode
71  /// If nthreads = 0 TMVA will use the default thread pool size
72  ////////////////////////////////////////////
73  explicit Executor(int nthreads) {
74  // enable MT in TMVA if :
75  // - no specific MT
76  if ( nthreads != 1 ) {
77 #ifdef R__USE_IMT
78  fMTExecImpl = std::unique_ptr< ROOT::TThreadExecutor>(new ROOT::TThreadExecutor(nthreads));
79 #else
80  ::Error("Executor","Cannot have TMVA in multi-threads mode when ROOT is built without IMT");
81 #endif
82  }
83  // case of single thread usage
84  if (!fMTExecImpl)
85  fSeqExecImpl = std::unique_ptr<ROOT::TSequentialExecutor>(new ROOT::TSequentialExecutor());
86  }
87 
88 #ifdef R__USE_IMT
89  ROOT::TThreadExecutor * GetMultiThreadExecutor() {
90  if (fMTExecImpl) return fMTExecImpl.get();
91  else {
92  fMTExecImpl = std::unique_ptr< ROOT::TThreadExecutor>(new ROOT::TThreadExecutor());
93  Info("GetThreadExecutor","Creating a TThread executor with a pool with a defult size of %d",fMTExecImpl->GetPoolSize());
94  return fMTExecImpl.get();
95  }
96  }
97 #endif
98 
99  unsigned int GetPoolSize() const {
100  if (!fMTExecImpl) return 1;
101 #ifdef R__USE_IMT
102  return fMTExecImpl->GetPoolSize();
103 #else
104  return 1;
105 #endif
106  }
107 
108  /// wrap TExecutor::Foreach
109  template<class Function>
110  void Foreach(Function func, unsigned int nTimes, unsigned nChunks = 0) {
111  if (fMTExecImpl) fMTExecImpl->Foreach(func,nTimes, nChunks);
112  else fSeqExecImpl->Foreach(func,nTimes);
113  }
114  template<class Function, class T>
115  void Foreach(Function func, std::vector<T> & args, unsigned nChunks = 0) {
116  if (fMTExecImpl) fMTExecImpl->Foreach(func,args, nChunks);
117  else fSeqExecImpl->Foreach(func, args);
118  }
119  template<class Function, class INTEGER>
120 #ifdef R__USE_IMT
121  void Foreach(Function func, ROOT::TSeq<INTEGER> args, unsigned nChunks = 0){
122  if (fMTExecImpl) fMTExecImpl->Foreach(func,args, nChunks);
123  else fSeqExecImpl->Foreach(func, args);
124  }
125 #else
126  void Foreach(Function func, ROOT::TSeq<INTEGER> args, unsigned /*nChunks*/ = 0){
127  fSeqExecImpl->Foreach(func, args);
128  }
129 #endif
130 
131  /// Wrap TExecutor::Map functions
132  template<class F, class Cond = noReferenceCond<F>>
133  auto Map(F func, unsigned nTimes) -> std::vector<typename std::result_of<F()>::type> {
134  if (fMTExecImpl) return fMTExecImpl->Map(func,nTimes);
135  else return fSeqExecImpl->Map(func, nTimes);
136  }
137  template<class F, class INTEGER, class Cond = noReferenceCond<F, INTEGER>>
138  auto Map(F func, ROOT::TSeq<INTEGER> args) -> std::vector<typename std::result_of<F(INTEGER)>::type> {
139  if (fMTExecImpl) return fMTExecImpl->Map(func,args);
140  else return fSeqExecImpl->Map(func, args);
141  }
142 
143  /// Wrap TExecutor::MapReduce functions
144  template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
145  auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc) -> typename std::result_of<F(INTEGER)>::type {
146  if (fMTExecImpl) return fMTExecImpl->MapReduce(func, args, redfunc);
147  else return fSeqExecImpl->MapReduce(func, args, redfunc);
148  }
149  template<class F, class INTEGER, class R, class Cond = noReferenceCond<F, INTEGER>>
150  auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> typename std::result_of<F(INTEGER)>::type {
151  if (fMTExecImpl) return fMTExecImpl->MapReduce(func, args, redfunc, nChunks);
152  else return fSeqExecImpl->MapReduce(func, args, redfunc);
153  }
154 
155  ///Wrap Reduce function
156  template<class T, class R>
157  auto Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs)) {
158  if (fMTExecImpl) return fMTExecImpl->Reduce(objs, redfunc);
159  else return fSeqExecImpl->Reduce(objs, redfunc);
160  }
161  //template<class T> T* Reduce(const std::vector<T*> &mergeObjs);
162 
163 #ifdef R__USE_IMT
164  std::unique_ptr<ROOT::TThreadExecutor> fMTExecImpl;
165 #else
166  std::unique_ptr<ROOT::TSequentialExecutor> fMTExecImpl; // if not using MT the two pointers will be of same type
167 #endif
168  std::unique_ptr<ROOT::TSequentialExecutor> fSeqExecImpl;
169 };
170 
171 } // end namespace TMVA
172 
173 #endif