Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TThreadExecutor.hxx
Go to the documentation of this file.
1// @(#)root/thread:$Id$
2// Author: Xavier Valls March 2016
3
4/*************************************************************************
5 * Copyright (C) 1995-2020, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#ifndef ROOT_TThreadExecutor
13#define ROOT_TThreadExecutor
14
15#include "RConfigure.h"
16
17// exclude in case ROOT does not have IMT support
18#ifndef R__USE_IMT
19// No need to error out for dictionaries.
20# if !defined(__ROOTCLING__) && !defined(G__DICTIONARY)
21#error "Cannot use ROOT::TThreadExecutor when build option imt=Off."
22# endif
23#else
24
26#include "ROOT/TSeq.hxx"
27#include "ROOT/TypeTraits.hxx" // InvokeResult
28#include "RTaskArena.hxx"
29#include "TError.h"
31
32#include <functional> //std::function
33#include <initializer_list>
34#include <memory>
35#include <numeric> //std::accumulate
36#include <type_traits> //std::enable_if
37#include <utility> //std::move
38#include <vector>
39
40namespace ROOT {
41
42 class TThreadExecutor: public TExecutorCRTP<TThreadExecutor> {
45 TThreadExecutor &pool, std::unique_ptr<ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl> rangeImpl,
46 const std::function<void(const ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl &)> &body);
47
48 public:
49
50 explicit TThreadExecutor(UInt_t nThreads = 0u);
51
54
55 // ForEach
56 //
57 template<class F>
58 void Foreach(F func, unsigned nTimes, unsigned nChunks = 0);
59 template<class F, class INTEGER>
60 void Foreach(F func, ROOT::TSeq<INTEGER> args, unsigned nChunks = 0);
61 template<class F, class T>
62 void Foreach(F func, std::initializer_list<T> args, unsigned nChunks = 0);
63 template<class F, class T>
64 void Foreach(F func, std::vector<T> &args, unsigned nChunks = 0);
65 template<class F, class T>
66 void Foreach(F func, const std::vector<T> &args, unsigned nChunks = 0);
67
68 // Map
69 //
71
72 // Extension of the Map interfaces with chunking, specific to this class
73 template <class F, class R, class Cond = validMapReturnCond<F>>
74 auto Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector<InvokeResult_t<F>>;
75 template <class F, class INTEGER, class R, class Cond = validMapReturnCond<F, INTEGER>>
76 auto Map(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks)
77 -> std::vector<InvokeResult_t<F, INTEGER>>;
78 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
79 auto Map(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> std::vector<InvokeResult_t<F, T>>;
80 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
81 auto Map(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> std::vector<InvokeResult_t<F, T>>;
82 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
83 auto Map(F func, const std::vector<T> &args, R redfunc, unsigned nChunks) -> std::vector<InvokeResult_t<F, T>>;
84
85 // MapReduce
86 //
87 // We need to reimplement the MapReduce interfaces to allow for parallel reduction, defined in
88 // this class but not in the base class.
89 //
90 // the late return types also check at compile-time whether redfunc is compatible with func,
91 // other than checking that func is compatible with the type of arguments.
92 // a static_assert check in TThreadExecutor::Reduce is used to check that redfunc is compatible with the type returned by func
94 template <class F, class R, class Cond = validMapReturnCond<F>>
95 auto MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t<F>;
96 template <class F, class R, class Cond = validMapReturnCond<F>>
97 auto MapReduce(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> InvokeResult_t<F>;
98 template <class F, class INTEGER, class R, class Cond = validMapReturnCond<F, INTEGER>>
99 auto MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks) -> InvokeResult_t<F, INTEGER>;
100 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
101 auto MapReduce(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks) -> InvokeResult_t<F, T>;
102 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
103 auto MapReduce(F func, std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>;
104 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
105 auto MapReduce(F func, const std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>;
106 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
107 auto MapReduce(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> InvokeResult_t<F, T>;
108 template <class F, class T, class R, class Cond = validMapReturnCond<F, T>>
109 auto MapReduce(F func, const std::vector<T> &args, R redfunc, unsigned nChunks) -> InvokeResult_t<F, T>;
110
112 template<class T, class R> auto Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));
113 template<class T, class BINARYOP> auto Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()));
114
115 unsigned GetPoolSize() const;
116
117 private:
118 // Implementation of the Map functions declared in the parent class (TExecutorCRTP)
119 //
120 template <class F, class Cond = validMapReturnCond<F>>
121 auto MapImpl(F func, unsigned nTimes) -> std::vector<InvokeResult_t<F>>;
122 template <class F, class INTEGER, class Cond = validMapReturnCond<F, INTEGER>>
123 auto MapImpl(F func, ROOT::TSeq<INTEGER> args) -> std::vector<InvokeResult_t<F, INTEGER>>;
124 template <class F, class T, class Cond = validMapReturnCond<F, T>>
125 auto MapImpl(F func, std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>;
126 template <class F, class T, class Cond = validMapReturnCond<F, T>>
127 auto MapImpl(F func, const std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>;
128
129 // Functions that interface with the parallel library used as a backend
130 void ParallelFor(unsigned start, unsigned end, unsigned step, const std::function<void(unsigned int i)> &f);
131 void ParallelFor(std::unique_ptr<ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl> rangeImpl,
132 const std::function<void(const ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl &)> &body);
133 double ParallelReduce(const std::vector<double> &objs, const std::function<double(double a, double b)> &redfunc);
134 float ParallelReduce(const std::vector<float> &objs, const std::function<float(float a, float b)> &redfunc);
135 template<class T, class R>
136 auto SeqReduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs));
137
138 /// Pointer to the TBB task arena wrapper
139 std::shared_ptr<ROOT::Internal::RTaskArenaWrapper> fTaskArenaW = nullptr;
140 };
141
142 /************ TEMPLATE METHODS IMPLEMENTATION ******************/
143
144 //////////////////////////////////////////////////////////////////////////
145 /// \brief Execute a function without arguments several times in parallel, dividing the execution in nChunks.
146 ///
147 /// \param func Function to be executed.
148 /// \param nTimes Number of times function should be called.
149 /// \param nChunks Number of chunks to split the input data for processing.
150 template<class F>
151 void TThreadExecutor::Foreach(F func, unsigned nTimes, unsigned nChunks) {
152 if (nChunks == 0) {
153 ParallelFor(0U, nTimes, 1, [&](unsigned int){func();});
154 return;
155 }
156
157 unsigned step = (nTimes + nChunks - 1) / nChunks;
158 auto lambda = [&](unsigned int i)
159 {
160 for (unsigned j = 0; j < step && (i + j) < nTimes; j++) {
161 func();
162 }
163 };
164 ParallelFor(0U, nTimes, step, lambda);
165 }
166
167 //////////////////////////////////////////////////////////////////////////
168 /// \brief Execute a function in parallel over a sequence of indexes, dividing the execution in nChunks.
169 ///
170 /// \param func Function to be executed. Must take an element of the sequence passed assecond argument as a parameter.
171 /// \param args Sequence of indexes to execute `func` on.
172 /// \param nChunks Number of chunks to split the input data for processing.
173 template<class F, class INTEGER>
174 void TThreadExecutor::Foreach(F func, ROOT::TSeq<INTEGER> args, unsigned nChunks) {
175 if (nChunks == 0) {
176 ParallelFor(*args.begin(), *args.end(), args.step(), [&](unsigned int i){func(i);});
177 return;
178 }
179 unsigned start = *args.begin();
180 unsigned end = *args.end();
181 unsigned seqStep = args.step();
182 unsigned step = (end - start + nChunks - 1) / nChunks; //ceiling the division
183
184 auto lambda = [&](unsigned int i)
185 {
186 for (unsigned j = 0; j < step && (i + j) < end; j+=seqStep) {
187 func(i + j);
188 }
189 };
190 ParallelFor(start, end, step, lambda);
191 }
192
193 //////////////////////////////////////////////////////////////////////////
194 /// \brief Execute a function in parallel over the elements of an initializer_list, dividing the execution in nChunks.
195 ///
196 /// \param func Function to be executed on the elements of the initializer_list passed as second parameter.
197 /// \param args initializer_list for a vector to apply `func` on.
198 /// \param nChunks Number of chunks to split the input data for processing.
199 template<class F, class T>
200 void TThreadExecutor::Foreach(F func, std::initializer_list<T> args, unsigned nChunks) {
201 std::vector<T> vargs(std::move(args));
202 Foreach(func, vargs, nChunks);
203 }
204
205 //////////////////////////////////////////////////////////////////////////
206 /// \brief Execute a function in parallel over the elements of a vector, dividing the execution in nChunks.
207 ///
208 /// \param func Function to be executed on the elements of the vector passed as second parameter.
209 /// \param args Vector of elements passed as an argument to `func`.
210 /// \param nChunks Number of chunks to split the input data for processing.
211 template<class F, class T>
212 void TThreadExecutor::Foreach(F func, std::vector<T> &args, unsigned nChunks) {
213 unsigned int nToProcess = args.size();
214 if (nChunks == 0) {
215 ParallelFor(0U, nToProcess, 1, [&](unsigned int i){func(args[i]);});
216 return;
217 }
218
219 unsigned step = (nToProcess + nChunks - 1) / nChunks; //ceiling the division
220 auto lambda = [&](unsigned int i)
221 {
222 for (unsigned j = 0; j < step && (i + j) < nToProcess; j++) {
223 func(args[i + j]);
224 }
225 };
226 ParallelFor(0U, nToProcess, step, lambda);
227 }
228
229 //////////////////////////////////////////////////////////////////////////
230 /// \brief Execute a function in parallel over the elements of a immutable vector, dividing the execution in nChunks.
231 ///
232 /// \param func Function to be executed on the elements of the vector passed as second parameter.
233 /// \param args Immutable vector of elements passed as an argument to `func`.
234 /// \param nChunks Number of chunks to split the input data for processing.
235 template<class F, class T>
236 void TThreadExecutor::Foreach(F func, const std::vector<T> &args, unsigned nChunks) {
237 unsigned int nToProcess = args.size();
238 if (nChunks == 0) {
239 ParallelFor(0U, nToProcess, 1, [&](unsigned int i){func(args[i]);});
240 return;
241 }
242
243 unsigned step = (nToProcess + nChunks - 1) / nChunks; //ceiling the division
244 auto lambda = [&](unsigned int i)
245 {
246 for (unsigned j = 0; j < step && (i + j) < nToProcess; j++) {
247 func(args[i + j]);
248 }
249 };
250 ParallelFor(0U, nToProcess, step, lambda);
251 }
252
253 //////////////////////////////////////////////////////////////////////////
254 /// \brief Execute a function without arguments several times in parallel.
255 /// Implementation of the Map method.
256 ///
257 /// \copydetails TExecutorCRTP::Map(F func,unsigned nTimes)
258 template <class F, class Cond>
259 auto TThreadExecutor::MapImpl(F func, unsigned nTimes) -> std::vector<InvokeResult_t<F>>
260 {
261 using retType = decltype(func());
262 std::vector<retType> reslist(nTimes);
263 auto lambda = [&](unsigned int i)
264 {
265 reslist[i] = func();
266 };
267 ParallelFor(0U, nTimes, 1, lambda);
268
269 return reslist;
270 }
271
272 //////////////////////////////////////////////////////////////////////////
273 /// \brief Execute a function over a sequence of indexes in parallel.
274 /// Implementation of the Map method.
275 ///
276 /// \copydetails TExecutorCRTP::Map(F func,ROOT::TSeq<INTEGER> args)
277 template <class F, class INTEGER, class Cond>
278 auto TThreadExecutor::MapImpl(F func, ROOT::TSeq<INTEGER> args) -> std::vector<InvokeResult_t<F, INTEGER>>
279 {
280 using retType = decltype(func(*args.begin()));
281 std::vector<retType> reslist(args.size());
282 auto lambda = [&](unsigned int i) { reslist[i] = func(args[i]); };
283 ParallelFor(0U, args.size(), 1, lambda);
284
285 return reslist;
286 }
287
288 //////////////////////////////////////////////////////////////////////////
289 /// \brief Execute a function `nTimes` in parallel, dividing the execution in nChunks and
290 /// providing a result per chunk.
291 ///
292 /// \copydetails ROOT::Internal::TExecutor::Map(F func,unsigned nTimes,R redfunc,unsigned nChunks)
293 template <class F, class R, class Cond>
294 auto TThreadExecutor::Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector<InvokeResult_t<F>>
295 {
296 if (nChunks == 0)
297 {
298 return Map(func, nTimes);
299 }
300
301 unsigned step = (nTimes + nChunks - 1) / nChunks;
302 // Avoid empty chunks
303 unsigned actualChunks = (nTimes + step - 1) / step;
304 using retType = decltype(func());
305 std::vector<retType> reslist(actualChunks);
306 auto lambda = [&](unsigned int i)
307 {
308 std::vector<retType> partialResults(std::min(nTimes-i, step));
309 for (unsigned j = 0; j < step && (i + j) < nTimes; j++) {
310 partialResults[j] = func();
311 }
312 reslist[i / step] = Reduce(partialResults, redfunc);
313 };
314 ParallelFor(0U, nTimes, step, lambda);
315
316 return reslist;
317 }
318
319 //////////////////////////////////////////////////////////////////////////
320 /// \brief Execute a function over the elements of a vector in parallel.
321 /// Implementation of the Map method.
322 ///
323 /// \copydetails TExecutorCRTP::Map(F func,std::vector<T> &args)
324 template <class F, class T, class Cond>
325 auto TThreadExecutor::MapImpl(F func, std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>
326 {
327 // //check whether func is callable
328 using retType = decltype(func(args.front()));
329
330 unsigned int nToProcess = args.size();
331 std::vector<retType> reslist(nToProcess);
332
333 auto lambda = [&](unsigned int i)
334 {
335 reslist[i] = func(args[i]);
336 };
337
338 ParallelFor(0U, nToProcess, 1, lambda);
339
340 return reslist;
341 }
342
343 //////////////////////////////////////////////////////////////////////////
344 /// \brief Execute a function over the elements of a vector in parallel.
345 /// Implementation of the Map method.
346 ///
347 /// \copydetails TExecutorCRTP::Map(F func,const std::vector<T> &args)
348 template <class F, class T, class Cond>
349 auto TThreadExecutor::MapImpl(F func, const std::vector<T> &args) -> std::vector<InvokeResult_t<F, T>>
350 {
351 // //check whether func is callable
352 using retType = decltype(func(args.front()));
353
354 unsigned int nToProcess = args.size();
355 std::vector<retType> reslist(nToProcess);
356
357 auto lambda = [&](unsigned int i)
358 {
359 reslist[i] = func(args[i]);
360 };
361
362 ParallelFor(0U, nToProcess, 1, lambda);
363
364 return reslist;
365 }
366
367 //////////////////////////////////////////////////////////////////////////
368 /// \brief Execute a function in parallel over the elements of a sequence, dividing the execution in nChunks and
369 /// providing a result per chunk.
370 ///
371 /// \copydetails ROOT::Internal::TExecutor::Map(F func,ROOT::TSeq<INTEGER> args,R redfunc,unsigned nChunks)
372 template <class F, class INTEGER, class R, class Cond>
373 auto TThreadExecutor::Map(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks)
374 -> std::vector<InvokeResult_t<F, INTEGER>>
375 {
376 if (nChunks == 0)
377 {
378 return Map(func, args);
379 }
380
381 unsigned nToProcess = args.size();
382 unsigned step = (nToProcess + nChunks - 1) / nChunks; // ceiling the division
383 // Avoid empty chunks
384 unsigned actualChunks = (nToProcess + step - 1) / step;
385
386 using retType = decltype(func(*args.begin()));
387 std::vector<retType> reslist(actualChunks);
388 auto lambda = [&](unsigned int i) {
389 std::vector<retType> partialResults(std::min(step, nToProcess - i)); // last chunk might be smaller
390 for (unsigned j = 0; j < partialResults.size(); j++) {
391 partialResults[j] = func(args[i + j]);
392 }
393 reslist[i / step] = Reduce(partialResults, redfunc);
394 };
395
396 ParallelFor(0U, nToProcess, step, lambda);
397
398 return reslist;
399 }
400
401 //////////////////////////////////////////////////////////////////////////
402 /// \brief Execute a function in parallel over the elements of a vector, dividing the execution in nChunks and
403 /// providing a result per chunk.
404 ///
405 /// \copydetails ROOT::Internal::TExecutor::Map(F func,std::vector<T> &args,R redfunc,unsigned nChunks)
406 template <class F, class T, class R, class Cond>
407 auto TThreadExecutor::Map(F func, std::vector<T> &args, R redfunc, unsigned nChunks)
408 -> std::vector<InvokeResult_t<F, T>>
409 {
410 if (nChunks == 0)
411 {
412 return Map(func, args);
413 }
414
415 unsigned int nToProcess = args.size();
416 unsigned step = (nToProcess + nChunks - 1) / nChunks; //ceiling the division
417 // Avoid empty chunks
418 unsigned actualChunks = (nToProcess + step - 1) / step;
419
420 using retType = decltype(func(args.front()));
421 std::vector<retType> reslist(actualChunks);
422 auto lambda = [&](unsigned int i) {
423 std::vector<retType> partialResults(std::min(step, nToProcess - i));
424 for (unsigned j = 0; j < partialResults.size(); j++) {
425 partialResults[j] = func(args[i + j]);
426 }
427 reslist[i / step] = Reduce(partialResults, redfunc);
428 };
429
430 ParallelFor(0U, nToProcess, step, lambda);
431
432 return reslist;
433 }
434
435 //////////////////////////////////////////////////////////////////////////
436 /// \brief Execute a function in parallel over the elements of an immutable vector, dividing the execution in nChunks and
437 /// providing a result per chunk.
438 ///
439 /// \copydetails ROOT::Internal::TExecutor::Map(F func,const std::vector<T> &args,R redfunc,unsigned nChunks)
440 template <class F, class T, class R, class Cond>
441 auto TThreadExecutor::Map(F func, const std::vector<T> &args, R redfunc, unsigned nChunks)
442 -> std::vector<InvokeResult_t<F, T>>
443 {
444 if (nChunks == 0)
445 {
446 return Map(func, args);
447 }
448
449 unsigned int nToProcess = args.size();
450 unsigned step = (nToProcess + nChunks - 1) / nChunks; //ceiling the division
451 // Avoid empty chunks
452 unsigned actualChunks = (nToProcess + step - 1) / step;
453
454 using retType = decltype(func(args.front()));
455 std::vector<retType> reslist(actualChunks);
456 auto lambda = [&](unsigned int i) {
457 std::vector<retType> partialResults(std::min(step, nToProcess - i));
458 for (unsigned j = 0; j < partialResults.size(); j++) {
459 partialResults[j] = func(args[i + j]);
460 }
461 reslist[i / step] = Reduce(partialResults, redfunc);
462 };
463
464 ParallelFor(0U, nToProcess, step, lambda);
465
466 return reslist;
467 }
468
469 //////////////////////////////////////////////////////////////////////////
470 /// \brief Execute a function in parallel over the elements of an initializer_list, dividing the execution in nChunks and
471 /// providing a result per chunk.
472 ///
473 /// \copydetails ROOT::Internal::TExecutor::Map(F func,std::initializer_list<T> args,R redfunc,unsigned nChunks)
474 template <class F, class T, class R, class Cond>
475 auto TThreadExecutor::Map(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks)
476 -> std::vector<InvokeResult_t<F, T>>
477 {
478 std::vector<T> vargs(std::move(args));
479 const auto &reslist = Map(func, vargs, redfunc, nChunks);
480 return reslist;
481 }
482
483 //////////////////////////////////////////////////////////////////////////
484 /// \brief Execute a function `nTimes` in parallel (Map) and accumulate the results into a single value (Reduce).
485 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,unsigned nTimes,R redfunc)
486 template <class F, class R, class Cond>
487 auto TThreadExecutor::MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t<F>
488 {
489 return Reduce(Map(func, nTimes), redfunc);
490 }
491
492 //////////////////////////////////////////////////////////////////////////
493 /// \brief Execute a function in parallel over the elements of a vector (Map) and accumulate the results into a single value (Reduce).
494 /// Benefits from partial reduction into `nChunks` intermediate results.
495 ///
496 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,unsigned nTimes,R redfunc,unsigned nChunks)
497 template <class F, class R, class Cond>
498 auto TThreadExecutor::MapReduce(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> InvokeResult_t<F>
499 {
500 return Reduce(Map(func, nTimes, redfunc, nChunks), redfunc);
501 }
502
503 //////////////////////////////////////////////////////////////////////////
504 /// \brief Execute a function in parallel over the elements of a vector (Map) and accumulate the results into a single value (Reduce).
505 /// Benefits from partial reduction into `nChunks` intermediate results.
506 ///
507 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,ROOT::TSeq<INTEGER> args,R redfunc,unsigned nChunks)
508 template <class F, class INTEGER, class R, class Cond>
509 auto TThreadExecutor::MapReduce(F func, ROOT::TSeq<INTEGER> args, R redfunc, unsigned nChunks)
511 {
512 return Reduce(Map(func, args, redfunc, nChunks), redfunc);
513 }
514
515 //////////////////////////////////////////////////////////////////////////
516 /// \brief Execute a function in parallel over the elements of an initializer_list (Map) and accumulate the results into a single value (Reduce).
517 /// Benefits from partial reduction into `nChunks` intermediate results.
518 ///
519 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,std::initializer_list<T> args,R redfunc,unsigned nChunks)
520 template <class F, class T, class R, class Cond>
521 auto TThreadExecutor::MapReduce(F func, std::initializer_list<T> args, R redfunc, unsigned nChunks)
523 {
524 return Reduce(Map(func, args, redfunc, nChunks), redfunc);
525 }
526
527 //////////////////////////////////////////////////////////////////////////
528 /// \brief Execute a function over the elements of a vector in parallel (Map) and accumulate the results into a single value (Reduce).
529 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,std::vector<T> &args,R redfunc)
530 template <class F, class T, class R, class Cond>
531 auto TThreadExecutor::MapReduce(F func, std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>
532 {
533 return Reduce(Map(func, args), redfunc);
534 }
535
536 //////////////////////////////////////////////////////////////////////////
537 /// \brief Execute a function over the elements of an immutable vector in parallel (Map) and accumulate the results into a single value (Reduce).
538 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,const std::vector<T> &args,R redfunc)
539 template <class F, class T, class R, class Cond>
540 auto TThreadExecutor::MapReduce(F func, const std::vector<T> &args, R redfunc) -> InvokeResult_t<F, T>
541 {
542 return Reduce(Map(func, args), redfunc);
543 }
544
545 //////////////////////////////////////////////////////////////////////////
546 /// \brief Execute a function in parallel over the elements of a vector (Map) and accumulate the results into a single value (Reduce).
547 /// Benefits from partial reduction into `nChunks` intermediate results.
548 ///
549 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,std::vector<T> &args,R redfunc,unsigned nChunks)
550 template <class F, class T, class R, class Cond>
551 auto TThreadExecutor::MapReduce(F func, std::vector<T> &args, R redfunc, unsigned nChunks) -> InvokeResult_t<F, T>
552 {
553 return Reduce(Map(func, args, redfunc, nChunks), redfunc);
554 }
555
556 //////////////////////////////////////////////////////////////////////////
557 /// \brief Execute a function in parallel over the elements of an immutable vector (Map) and accumulate the results into a single value (Reduce).
558 /// Benefits from partial reduction into `nChunks` intermediate results.
559 ///
560 /// \copydetails ROOT::Internal::TExecutor::MapReduce(F func,const std::vector<T> &args,R redfunc,unsigned nChunks)
561 template <class F, class T, class R, class Cond>
562 auto TThreadExecutor::MapReduce(F func, const std::vector<T> &args, R redfunc, unsigned nChunks)
564 {
565 return Reduce(Map(func, args, redfunc, nChunks), redfunc);
566 }
567
568 //////////////////////////////////////////////////////////////////////////
569 /// \copydoc ROOT::Internal::TExecutor::Reduce(const std::vector<T> &objs,R redfunc)
570 template<class T, class R>
571 auto TThreadExecutor::Reduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
572 {
573 // check we can apply reduce to objs
574 static_assert(std::is_same<decltype(redfunc(objs)), T>::value, "redfunc does not have the correct signature");
575 return SeqReduce(objs, redfunc);
576 }
577
578 //////////////////////////////////////////////////////////////////////////
579 /// \brief "Reduce" an std::vector into a single object in parallel by passing a
580 /// binary function as the second argument defining the reduction operation.
581 ///
582 /// \param objs A vector of elements to combine.
583 /// \param redfunc Binary reduction function to combine the elements of the vector `objs`.
584 /// \return A value result of combining the vector elements into a single object of the same type.
585 template<class T, class BINARYOP>
586 auto TThreadExecutor::Reduce(const std::vector<T> &objs, BINARYOP redfunc) -> decltype(redfunc(objs.front(), objs.front()))
587 {
588 // check we can apply reduce to objs
589 static_assert(std::is_same<decltype(redfunc(objs.front(), objs.front())), T>::value, "redfunc does not have the correct signature");
590 return ParallelReduce(objs, redfunc);
591 }
592
593 //////////////////////////////////////////////////////////////////////////
594 /// \brief "Reduce", sequentially, an std::vector into a single object
595 ///
596 /// \param objs A vector of elements to combine.
597 /// \param redfunc Reduction function to combine the elements of the vector `objs`.
598 /// \return A value result of combining the vector elements into a single object of the same type.
599 template<class T, class R>
600 auto TThreadExecutor::SeqReduce(const std::vector<T> &objs, R redfunc) -> decltype(redfunc(objs))
601 {
602 return redfunc(objs);
603 }
604
605} // namespace ROOT
606
607#endif // R__USE_IMT
608#endif
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define a(i)
Definition RSha256.hxx:99
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Abstract implementation of the oneAPI Range requirements.
This class defines an interface to execute the same task multiple times, possibly in parallel and wit...
ROOT::TypeTraits::InvokeResult_t< F, Args... > InvokeResult_t
A pseudo container class which is a generator of indices.
Definition TSeq.hxx:67
iterator begin() const
Definition TSeq.hxx:172
T step() const
Definition TSeq.hxx:193
iterator end() const
Definition TSeq.hxx:175
This class provides a simple interface to execute the same task multiple times in parallel threads,...
auto SeqReduce(const std::vector< T > &objs, R redfunc) -> decltype(redfunc(objs))
"Reduce", sequentially, an std::vector into a single object
auto Map(F func, unsigned nTimes, R redfunc, unsigned nChunks) -> std::vector< InvokeResult_t< F > >
Execute a function nTimes in parallel, dividing the execution in nChunks and providing a result per c...
unsigned GetPoolSize() const
Returns the number of worker threads in the task arena.
friend void ROOT::Internal::IMTUtils::ParallelFor(TThreadExecutor &pool, std::unique_ptr< ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl > rangeImpl, const std::function< void(const ROOT::Internal::IMTUtils::RAbstractTBBRangeImpl &)> &body)
auto MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t< F >
Execute a function nTimes in parallel (Map) and accumulate the results into a single value (Reduce).
std::shared_ptr< ROOT::Internal::RTaskArenaWrapper > fTaskArenaW
Pointer to the TBB task arena wrapper.
auto Reduce(const std::vector< T > &objs, R redfunc) -> decltype(redfunc(objs))
"Reduce" an std::vector into a single object by passing a function as the second argument defining th...
void Foreach(F func, unsigned nTimes, unsigned nChunks=0)
Execute a function without arguments several times in parallel, dividing the execution in nChunks.
TThreadExecutor(UInt_t nThreads=0u)
Class constructor.
double ParallelReduce(const std::vector< double > &objs, const std::function< double(double a, double b)> &redfunc)
"Reduce" in parallel an std::vector<double> into a single double value
TThreadExecutor & operator=(const TThreadExecutor &)=delete
TThreadExecutor(const TThreadExecutor &)=delete
auto MapImpl(F func, unsigned nTimes) -> std::vector< InvokeResult_t< F > >
Execute a function without arguments several times in parallel.
void ParallelFor(ROOT::TThreadExecutor &pool, std::unique_ptr< RAbstractTBBRangeImpl > rangeImpl, const std::function< void(const RAbstractTBBRangeImpl &)> &body)