1 // -*- C++ -*-
2 /**
3 * @brief This file supplies support for multithreading
4 *
5 * Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6 *
7 * This library is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21 #ifndef OPENTURNS_TBB_HXX
22 #define OPENTURNS_TBB_HXX
23
24 #include <algorithm>
25 #include "openturns/OTprivate.hxx"
26 #include "openturns/OTconfig.hxx"
27 #include "openturns/Exception.hxx"
28
29 #ifdef OPENTURNS_HAVE_TBB
30 #ifdef OPENTURNS_TBB_NO_IMPLICIT_LINKAGE
31 # ifndef __TBB_NO_IMPLICIT_LINKAGE
32 # define __TBB_NO_IMPLICIT_LINKAGE 1
33 # endif
34 # ifndef __TBBMALLOC_NO_IMPLICIT_LINKAGE
35 # define __TBBMALLOC_NO_IMPLICIT_LINKAGE 1
36 # endif
37 #endif
38 #include <tbb/task_arena.h>
39 #include <tbb/parallel_sort.h>
40 #include <tbb/parallel_reduce.h>
41 #else /* OPENTURNS_HAVE_TBB */
42
43 // We redefine some TBB elements to simulate TBB availability through the code
44 // Those redefinitions are single threaded
45 namespace tbb
46 {
47
48 template <typename T>
49 class blocked_range
50 {
51 public:
52 typedef T value_type;
53 typedef std::size_t size_type;
blocked_range(value_type from,value_type to,size_type gs=1)54 blocked_range(value_type from, value_type to, size_type gs = 1)
55 : from_(from), to_(to), grainSize_(gs)
56 {
57 #ifdef DEBUG_BOUNDCHECKING
58 if (from_ > to_)
59 throw OT::InvalidArgumentException(HERE) << "Range is malformed (from > to) with from=" << from_
60 << " and to=" << to;
61 if (grainSize_ < 1)
62 throw OT::InvalidArgumentException(HERE) << "Range is malformed (grainSize < 1) with grainSize=" << grainSize_;
63 #endif /* DEBUG_BOUNDCHECKING */
64 }
begin() const65 value_type begin() const
66 {
67 return from_;
68 }
end() const69 value_type end() const
70 {
71 return to_;
72 }
size() const73 size_type size() const
74 {
75 return size_t(to_ - from_);
76 }
grainsize() const77 size_type grainsize() const
78 {
79 return grainSize_;
80 }
81 private:
82 value_type from_;
83 value_type to_;
84 size_type grainSize_;
85 }; // end class blocked_range
86
87 template <typename RANGE, typename BODY>
parallel_for(const RANGE & range,const BODY & body)88 void parallel_for(const RANGE & range, const BODY & body)
89 {
90 body( range );
91 }
92
93 template <typename RANGE, typename BODY>
parallel_reduce(const RANGE & range,BODY & body)94 void parallel_reduce(const RANGE & range, BODY & body)
95 {
96 body( range );
97 }
98
99 template <typename ITERATOR>
parallel_sort(ITERATOR first,ITERATOR last)100 void parallel_sort(ITERATOR first, ITERATOR last)
101 {
102 std::stable_sort(first, last);
103 }
104
105 class task_arena
106 {
107 public:
task_arena(int)108 task_arena(int) {}
execute(const F & f)109 template<typename F> void execute(const F& f)
110 {
111 f();
112 }
113 };
114
115 } // namespace tbb
116 #endif /* OPENTURNS_HAVE_TBB */
117
118 BEGIN_NAMESPACE_OPENTURNS
119
120 // disables blas threading inside TBB parallel regions
121 class TBBContext
122 {
123 public:
124 TBBContext();
125 ~TBBContext();
126 private:
127 int ompNumThreads_;
128 int openblasNumThreads_;
129 };
130
131 class OT_API TBB
132 {
133 public:
134 #ifndef SWIG // swig fails to parse nested struct or template
135
136 #ifdef OPENTURNS_HAVE_TBB
137 typedef tbb::split Split;
138 #else /* OPENTURNS_HAVE_TBB */
139 struct Split {};
140 #endif /* OPENTURNS_HAVE_TBB */
141
142 template <typename T>
143 struct BlockedRange : public tbb::blocked_range<T>
144 {
145 typedef T value_type;
146 typedef typename tbb::blocked_range<T>::size_type size_type;
BlockedRangeTBB::BlockedRange147 BlockedRange(value_type from, value_type to, size_type gs = 1) : tbb::blocked_range<T>(from, to, gs) {}
BlockedRangeTBB::BlockedRange148 BlockedRange(const tbb::blocked_range<T> & range) : tbb::blocked_range<T>(range) {}
149 };
150 #endif // SWIG
151
152 template <typename BODY>
153 static inline
ParallelFor(UnsignedInteger from,UnsignedInteger to,const BODY & body,std::size_t gs=1)154 void ParallelFor( UnsignedInteger from, UnsignedInteger to, const BODY & body, std::size_t gs = 1 )
155 {
156 TBBContext context;
157 P_task_arena_->execute([&]()
158 {
159 tbb::parallel_for(tbb::blocked_range<UnsignedInteger>(from, to, gs), body);
160 });
161 }
162
163 template <typename BODY>
164 static inline
ParallelForIf(const Bool condition,UnsignedInteger from,UnsignedInteger to,const BODY & body,std::size_t gs=1)165 void ParallelForIf(const Bool condition, UnsignedInteger from, UnsignedInteger to, const BODY & body, std::size_t gs = 1)
166 {
167 if (condition)
168 ParallelFor(from, to, body, gs);
169 else
170 body(tbb::blocked_range<UnsignedInteger>(from, to, gs));
171 }
172
173 template <typename BODY>
174 static inline
ParallelReduce(UnsignedInteger from,UnsignedInteger to,BODY & body,std::size_t gs=1)175 void ParallelReduce( UnsignedInteger from, UnsignedInteger to, BODY & body, std::size_t gs = 1)
176 {
177 TBBContext context;
178 P_task_arena_->execute([&]()
179 {
180 tbb::parallel_reduce(tbb::blocked_range<UnsignedInteger>(from, to, gs), body);
181 });
182 }
183
184 template <typename BODY>
185 static inline
ParallelReduceIf(const Bool condition,UnsignedInteger from,UnsignedInteger to,BODY & body,std::size_t gs=1)186 void ParallelReduceIf(const Bool condition, UnsignedInteger from, UnsignedInteger to, BODY & body, std::size_t gs = 1)
187 {
188 if (condition)
189 ParallelReduce(from, to, body, gs);
190 else
191 body(tbb::blocked_range<UnsignedInteger>(from, to, gs));
192 }
193
194 template <typename ITERATOR>
195 static inline
ParallelSort(ITERATOR first,ITERATOR last)196 void ParallelSort( ITERATOR first, ITERATOR last )
197 {
198 TBBContext context;
199 tbb::task_arena arena(ThreadsNumber_);
200 P_task_arena_->execute([&]()
201 {
202 tbb::parallel_sort(first, last);
203 });
204 }
205
206 /* Whether TBB is available */
207 static Bool IsAvailable();
208
209 /* Enable/disable */
210 static void Enable();
211 static void Disable();
212
213 /* Accessor to the maximum number of threads */
214 static void SetThreadsNumber(const UnsignedInteger threadsNumber);
215 static UnsignedInteger GetThreadsNumber();
216
217 /** @deprecated */
218 static void SetNumberOfThreads(const UnsignedInteger numberOfThreads);
219 static UnsignedInteger GetNumberOfThreads();
220
221 private:
222 friend struct TBB_init;
223
224 static UnsignedInteger ThreadsNumber_;
225 static tbb::task_arena * P_task_arena_;
226
227 }; /* end class TBB */
228
229 /** This struct initializes all static members of TBB */
230 struct OT_API TBB_init
231 {
232 TBB_init();
233 ~TBB_init();
234 }; /* end class TBB_init */
235
236 END_NAMESPACE_OPENTURNS
237
238 #endif /* OPENTURNS_TBB_HXX */
239