SPH
ThreadLocal.h
Go to the documentation of this file.
1 #pragma once
2 
7 
11 #include "thread/Scheduler.h"
12 
14 
15 namespace Detail {
16 
17 struct ValueInitTag {};
18 struct FunctorInitTag {};
19 
20 template <typename... TArgs>
21 struct ParamTraits {
22  using Tag = ValueInitTag;
23 };
24 template <typename TArg>
25 struct ParamTraits<TArg> {
26  using Tag = std::conditional_t<IsCallable<TArg>::value, FunctorInitTag, ValueInitTag>;
27 };
28 
29 } // namespace Detail
30 
35 template <typename Type>
36 class ThreadLocal {
37  // befriend other ThreadLocal classes
38  template <typename>
39  friend class ThreadLocal;
40 
41 private:
42  struct Local {
43  uint8_t padd1[64];
44  Type value;
45  uint8_t padd2[64];
46 
47  template <typename... TArgs>
48  Local(TArgs&&... args)
49  : value(std::forward<TArgs>(args)...) {}
50  };
51 
53  Array<Local> locals;
54 
56  IScheduler& scheduler;
57 
58  struct Sum {
59  INLINE constexpr Type operator()(const Type& t1, const Type& t2) const {
60  return t1 + t2;
61  }
62  };
63 
64 public:
69  template <typename... TArgs>
70  ThreadLocal(IScheduler& scheduler, TArgs&&... args)
71  : scheduler(scheduler) {
72  initialize(typename Detail::ParamTraits<TArgs...>::Tag{}, std::forward<TArgs>(args)...);
73  }
74 
79  template <typename TFunctor>
80  ThreadLocal(IScheduler& scheduler, TFunctor&& functor)
81  : scheduler(scheduler) {
82  initialize(typename Detail::ParamTraits<TFunctor>::Tag{}, std::forward<TFunctor>(functor));
83  }
84 
88  INLINE Type& local() {
89  const Optional<Size> idx = scheduler.getThreadIdx();
90  SPH_ASSERT(idx && idx.value() < locals.size());
91  return locals[idx.value()].value;
92  }
93 
95  INLINE const Type& local() const {
96  const Optional<Size> idx = scheduler.getThreadIdx();
97  SPH_ASSERT(idx && idx.value() < locals.size());
98  return locals[idx.value()].value;
99  }
100 
105  INLINE Type& value(const Size threadId) {
106  return locals[threadId].value;
107  }
108 
113  Type accumulate(const Type& initial = Type(0._f)) const {
114  return this->accumulate(initial, Sum{});
115  }
116 
122  template <typename TPredicate>
123  Type accumulate(const Type& initial, const TPredicate& predicate) const {
124  Type sum = initial;
125  for (const Type& value : *this) {
126  sum = predicate(sum, value);
127  }
128  return sum;
129  }
130 
131  template <typename T>
132  class LocalIterator : public Iterator<T> {
133  public:
135  : Iterator<T>(iter) {}
136 
137  using Return = std::conditional_t<std::is_const<T>::value, const Type&, Type&>;
138 
140  return this->data->value;
141  }
142  };
143 
146  return locals.begin();
147  }
148 
151  return locals.begin();
152  }
153 
156  return locals.end();
157  }
158 
161  return locals.end();
162  }
163 
164 private:
165  template <typename... TArgs>
166  void initialize(Detail::ValueInitTag, TArgs&&... args) {
167  const Size threadCnt = scheduler.getThreadCnt();
168  locals.reserve(threadCnt);
169  for (Size i = 0; i < threadCnt; ++i) {
170  // intentionally not forwarded, we cannot move parameters if we have more than one object
171  locals.emplaceBack(args...);
172  }
173  }
174 
175  template <typename TFunctor>
176  void initialize(Detail::FunctorInitTag, TFunctor&& functor) {
177  const Size threadCnt = scheduler.getThreadCnt();
178  locals.reserve(threadCnt);
179  for (Size i = 0; i < threadCnt; ++i) {
180  locals.emplaceBack(functor());
181  }
182  }
183 };
184 
186 template <typename Type, typename TFunctor>
187 INLINE void parallelFor(IScheduler& scheduler,
188  ThreadLocal<Type>& storage,
189  const Size from,
190  const Size to,
191  TFunctor&& functor) {
192  const Size granularity = scheduler.getRecommendedGranularity();
193  parallelFor(scheduler, storage, from, to, granularity, std::forward<TFunctor>(functor));
194 }
195 
197 template <typename Type, typename TFunctor>
198 INLINE void parallelFor(IScheduler& scheduler,
199  ThreadLocal<Type>& storage,
200  const Size from,
201  const Size to,
202  const Size granularity,
203  TFunctor&& functor) {
204  SPH_ASSERT(from <= to);
205 
206  scheduler.parallelFor(from, to, granularity, [&storage, &functor](Size n1, Size n2) {
207  SPH_ASSERT(n1 < n2);
208  Type& value = storage.local();
209  for (Size i = n1; i < n2; ++i) {
210  functor(i, value);
211  }
212  });
213 }
214 
Generic dynamically allocated resizable storage.
#define SPH_ASSERT(x,...)
Definition: Assert.h:94
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
Ordinary iterator for custom containers.
#define INLINE
Macros for conditional compilation based on selected compiler.
Definition: Object.h:31
#define NAMESPACE_SPH_END
Definition: Object.h:12
Wrapper of type value of which may or may not be present.
Interface for executing tasks (potentially) asynchronously.
INLINE void parallelFor(IScheduler &scheduler, ThreadLocal< Type > &storage, const Size from, const Size to, TFunctor &&functor)
Overload of parallelFor that passes thread-local storage into the functor.
Definition: ThreadLocal.h:187
void reserve(const TCounter newMaxSize)
Allocates enough memory to store the given number of elements.
Definition: Array.h:279
INLINE Iterator< StorageType > end() noexcept
Definition: Array.h:462
StorageType & emplaceBack(TArgs &&... args)
Constructs a new element at the end of the array in place, using the provided arguments.
Definition: Array.h:332
INLINE TCounter size() const noexcept
Definition: Array.h:193
INLINE Iterator< StorageType > begin() noexcept
Definition: Array.h:450
Interface that allows unified implementation of sequential and parallelized versions of algorithms.
Definition: Scheduler.h:27
virtual Optional< Size > getThreadIdx() const =0
Returns the index of the calling thread.
virtual void parallelFor(const Size from, const Size to, const Size granularity, const Function< void(Size n1, Size n2)> &functor)
Processes the given range concurrently.
Definition: Scheduler.cpp:46
virtual Size getRecommendedGranularity() const =0
Returns a value of granularity that is expected to perform well with the current thread count.
virtual Size getThreadCnt() const =0
Returns the number of threads used by this scheduler.
Simple (forward) iterator over continuous array of objects of type T.
Definition: Iterator.h:18
T * data
Definition: Iterator.h:22
INLINE Type & value()
Returns the reference to the stored value.
Definition: Optional.h:172
LocalIterator(Iterator< T > iter)
Definition: ThreadLocal.h:134
INLINE Return operator*() const
Definition: ThreadLocal.h:139
std::conditional_t< std::is_const< T >::value, const Type &, Type & > Return
Definition: ThreadLocal.h:137
Template for storing a copy of a value for every thread in given scheduler.
Definition: ThreadLocal.h:36
Type accumulate(const Type &initial, const TPredicate &predicate) const
Performs an accumulation of thread-local values.
Definition: ThreadLocal.h:123
LocalIterator< Local > begin()
Returns the iterator to the first element in the thread-local storage.
Definition: ThreadLocal.h:145
ThreadLocal(IScheduler &scheduler, TFunctor &&functor)
Constructs a thread-local storage using a functor.
Definition: ThreadLocal.h:80
LocalIterator< Local > end()
Returns the iterator to the first element in the thread-local storage.
Definition: ThreadLocal.h:155
INLINE Type & local()
Return a value for current thread.
Definition: ThreadLocal.h:88
LocalIterator< const Local > end() const
Returns the iterator to the first element in the thread-local storage.
Definition: ThreadLocal.h:160
Type accumulate(const Type &initial=Type(0._f)) const
Performs an accumulation of thread-local values.
Definition: ThreadLocal.h:113
ThreadLocal(IScheduler &scheduler, TArgs &&... args)
Constructs a thread-local storage from a list of values.
Definition: ThreadLocal.h:70
INLINE Type & value(const Size threadId)
Returns the storage corresponding to the thread with given index.
Definition: ThreadLocal.h:105
INLINE const Type & local() const
Return a value for current thread.
Definition: ThreadLocal.h:95
LocalIterator< const Local > begin() const
Returns the iterator to the first element in the thread-local storage.
Definition: ThreadLocal.h:150
constexpr Size sum()
Definition: Multipole.h:31
Overload of std::swap for Sph::Array.
Definition: Array.h:578
std::conditional_t< IsCallable< TArg >::value, FunctorInitTag, ValueInitTag > Tag
Definition: ThreadLocal.h:26