Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tbbWrap.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file tbbWrap.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2022 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #pragma once
10 
11 // uncomment to remove all use of tbb library.
12 // #define ACTS_EXAMPLES_NO_TBB
13 
14 #ifdef ACTS_EXAMPLES_NO_TBB
15 #define ACTS_EXAMPLES_WITH_TBB(a)
16 #include <stdexcept>
17 #else
18 #define ACTS_EXAMPLES_WITH_TBB(a) a
19 #include <optional>
20 
21 #include <tbb/parallel_for.h>
22 #include <tbb/queuing_mutex.h>
23 #include <tbb/task_arena.h>
24 #endif
25 
26 namespace ActsExamples {
27 
43 
44 #ifdef ACTS_EXAMPLES_NO_TBB
45 namespace tbb {
46 namespace task_arena {
47 constexpr int automatic = -1;
48 }
49 
50 template <typename Value>
51 struct blocked_range {
52  blocked_range(Value begin_, Value end_) : my_end(end_), my_begin(begin_) {}
53  Value begin() const { return my_begin; }
54  Value end() const { return my_end; }
55 
56  private:
57  Value my_end;
58  Value my_begin;
59 };
60 } // namespace tbb
61 #endif
62 
63 namespace tbbWrap {
69 static bool enableTBB(int nthreads = -99) {
70  static bool setting = false;
71  if (nthreads != -99) {
72 #ifdef ACTS_EXAMPLES_NO_TBB
73  if (nthreads > 1) {
74  throw std::runtime_error(
75  "tbb is not available, so can't do multi-threading.");
76  }
77 #else
78  bool newSetting = (nthreads != 1);
79  if (!setting && newSetting) {
80  setting = newSetting;
81  }
82 #endif
83  }
84  return setting;
85 }
86 
91 class task_arena {
92 #ifndef ACTS_EXAMPLES_NO_TBB
93  std::optional<tbb::task_arena> tbb;
94 #endif
95 
96  public:
97  task_arena(int nthreads = tbb::task_arena::automatic,
98  unsigned ACTS_EXAMPLES_WITH_TBB(res) = 1) {
99  if (enableTBB(nthreads)) {
100 #ifndef ACTS_EXAMPLES_NO_TBB
101  tbb.emplace(nthreads, res);
102 #endif
103  }
104  }
105 
106  template <typename F>
107  void execute(const F& f) {
108 #ifndef ACTS_EXAMPLES_NO_TBB
109  if (tbb) {
110  tbb->execute(f);
111  } else
112 #endif
113  {
114  f();
115  }
116  }
117 };
118 
121  public:
122  template <typename R, typename F>
123  parallel_for(const R& r, const F& f) {
124 #ifndef ACTS_EXAMPLES_NO_TBB
125  if (enableTBB()) {
126  tbb::parallel_for(r, f);
127  } else
128 #endif
129  {
130  for (auto i = r.begin(); i != r.end(); ++i) { // use default grainsize=1
131  f(R(i, i + 1));
132  }
133  }
134  }
135 };
136 
139 #ifndef ACTS_EXAMPLES_NO_TBB
140  std::optional<tbb::queuing_mutex> tbb;
141 #endif
142 
143  public:
145 #ifndef ACTS_EXAMPLES_NO_TBB
146  if (enableTBB()) {
147  tbb.emplace();
148  }
149 #endif
150  }
151 
152  class scoped_lock {
153 #ifndef ACTS_EXAMPLES_NO_TBB
154  std::optional<tbb::queuing_mutex::scoped_lock> tbb;
155 #endif
156 
157  public:
159 #ifndef ACTS_EXAMPLES_NO_TBB
160  if (enableTBB()) {
161  tbb.emplace();
162  }
163 #endif
164  }
165 
167 #ifndef ACTS_EXAMPLES_NO_TBB
168  if (enableTBB()) {
169  tbb.emplace(*m.tbb);
170  }
171 #endif
172  }
173  };
174 };
175 
176 } // namespace tbbWrap
177 } // namespace ActsExamples