Eigen::RunQueue< Work, kSize > Class Template Reference

#include <RunQueue.h>

Classes

struct  Elem
 

Public Member Functions

 RunQueue ()
 
 ~RunQueue ()
 
Work PushFront (Work w)
 
Work PopFront ()
 
Work PushBack (Work w)
 
Work PopBack ()
 
unsigned PopBackHalf (std::vector< Work > *result)
 
unsigned Size () const
 
bool Empty () const
 
void Flush ()
 

Private Types

enum  State { kEmpty , kBusy , kReady }
 

Private Member Functions

template<bool NeedSizeEstimate>
unsigned SizeOrNotEmpty () const
 
EIGEN_ALWAYS_INLINE unsigned CalculateSize (unsigned front, unsigned back) const
 
 RunQueue (const RunQueue &)=delete
 
void operator= (const RunQueue &)=delete
 

Private Attributes

EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic< unsignedfront_
 
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic< unsignedback_
 
EIGEN_MUTEX mutex_
 
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING Elem array_ [kSize]
 

Static Private Attributes

static const unsigned kMask = kSize - 1
 
static const unsigned kMask2 = (kSize << 1) - 1
 

Member Enumeration Documentation

◆ State

template<typename Work , unsigned kSize>
enum Eigen::RunQueue::State
private
Enumerator
kEmpty 
kBusy 
kReady 
158  {
159  kEmpty,
160  kBusy,
161  kReady,
162  };
@ kReady
Definition: RunQueue.h:161
@ kEmpty
Definition: RunQueue.h:159
@ kBusy
Definition: RunQueue.h:160

Constructor & Destructor Documentation

◆ RunQueue() [1/2]

template<typename Work , unsigned kSize>
Eigen::RunQueue< Work, kSize >::RunQueue ( )
inline
43  : front_(0), back_(0) {
44  // require power-of-two for fast masking
45  eigen_plain_assert((kSize & (kSize - 1)) == 0);
46  eigen_plain_assert(kSize > 2); // why would you do this?
47  eigen_plain_assert(kSize <= (64 << 10)); // leave enough space for counter
48  for (unsigned i = 0; i < kSize; i++) array_[i].state.store(kEmpty, std::memory_order_relaxed);
49  }
#define eigen_plain_assert(condition)
Definition: Assert.h:148
int i
Definition: BiCGSTAB_step_by_step.cpp:9
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic< unsigned > back_
Definition: RunQueue.h:177
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING std::atomic< unsigned > front_
Definition: RunQueue.h:176
EIGEN_ALIGN_TO_AVOID_FALSE_SHARING Elem array_[kSize]
Definition: RunQueue.h:180

References Eigen::RunQueue< Work, kSize >::array_, eigen_plain_assert, i, and Eigen::RunQueue< Work, kSize >::kEmpty.

◆ ~RunQueue()

template<typename Work , unsigned kSize>
Eigen::RunQueue< Work, kSize >::~RunQueue ( )
inline
51 { eigen_plain_assert(Size() == 0); }
unsigned Size() const
Definition: RunQueue.h:141

References eigen_plain_assert, and Eigen::RunQueue< Work, kSize >::Size().

◆ RunQueue() [2/2]

template<typename Work , unsigned kSize>
Eigen::RunQueue< Work, kSize >::RunQueue ( const RunQueue< Work, kSize > &  )
privatedelete

Member Function Documentation

◆ CalculateSize()

template<typename Work , unsigned kSize>
EIGEN_ALWAYS_INLINE unsigned Eigen::RunQueue< Work, kSize >::CalculateSize ( unsigned  front,
unsigned  back 
) const
inlineprivate
212  {
213  int size = (front & kMask2) - (back & kMask2);
214  // Fix overflow.
215  if (EIGEN_PREDICT_FALSE(size < 0)) size += 2 * kSize;
216  // Order of modification in push/pop is crafted to make the queue look
217  // larger than it is during concurrent modifications. E.g. push can
218  // increment size before the corresponding pop has decremented it.
219  // So the computed size can be up to kSize + 1, fix it.
220  if (EIGEN_PREDICT_FALSE(size > static_cast<int>(kSize))) size = kSize;
221  return static_cast<unsigned>(size);
222  }
#define EIGEN_PREDICT_FALSE(x)
Definition: Macros.h:1179
Scalar Scalar int size
Definition: benchVecAdd.cpp:17
static const unsigned kMask2
Definition: RunQueue.h:156

References EIGEN_PREDICT_FALSE, Eigen::RunQueue< Work, kSize >::kMask2, and size.

Referenced by Eigen::RunQueue< Work, kSize >::SizeOrNotEmpty().

◆ Empty()

template<typename Work , unsigned kSize>
bool Eigen::RunQueue< Work, kSize >::Empty ( ) const
inline

◆ Flush()

template<typename Work , unsigned kSize>
void Eigen::RunQueue< Work, kSize >::Flush ( )
inline
148  {
149  while (!Empty()) {
150  PopFront();
151  }
152  }
Work PopFront()
Definition: RunQueue.h:68
bool Empty() const
Definition: RunQueue.h:145

References Eigen::RunQueue< Work, kSize >::Empty(), and Eigen::RunQueue< Work, kSize >::PopFront().

◆ operator=()

template<typename Work , unsigned kSize>
void Eigen::RunQueue< Work, kSize >::operator= ( const RunQueue< Work, kSize > &  )
privatedelete

◆ PopBack()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PopBack ( )
inline
96  {
97  if (Empty()) return Work();
98  EIGEN_MUTEX_LOCK lock(mutex_);
99  unsigned back = back_.load(std::memory_order_relaxed);
100  Elem* e = &array_[back & kMask];
101  uint8_t s = e->state.load(std::memory_order_relaxed);
102  if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return Work();
103  Work w = std::move(e->w);
104  e->state.store(kEmpty, std::memory_order_release);
105  back_.store(back + 1 + (kSize << 1), std::memory_order_relaxed);
106  return w;
107  }
Array< double, 1, 3 > e(1./3., 0.5, 2.)
RowVector3d w
Definition: Matrix_resize_int.cpp:3
EIGEN_MUTEX mutex_
Definition: RunQueue.h:178
static const unsigned kMask
Definition: RunQueue.h:155
RealScalar s
Definition: level1_cplx_impl.h:130
std::uint8_t uint8_t
Definition: Meta.h:36

References Eigen::RunQueue< Work, kSize >::array_, Eigen::RunQueue< Work, kSize >::back_, e(), Eigen::RunQueue< Work, kSize >::Empty(), Eigen::RunQueue< Work, kSize >::kBusy, Eigen::RunQueue< Work, kSize >::kEmpty, Eigen::RunQueue< Work, kSize >::kMask, Eigen::RunQueue< Work, kSize >::kReady, Eigen::RunQueue< Work, kSize >::mutex_, s, and w.

◆ PopBackHalf()

template<typename Work , unsigned kSize>
unsigned Eigen::RunQueue< Work, kSize >::PopBackHalf ( std::vector< Work > *  result)
inline
111  {
112  if (Empty()) return 0;
113  EIGEN_MUTEX_LOCK lock(mutex_);
114  unsigned back = back_.load(std::memory_order_relaxed);
115  unsigned size = Size();
116  unsigned mid = back;
117  if (size > 1) mid = back + (size - 1) / 2;
118  unsigned n = 0;
119  unsigned start = 0;
120  for (; static_cast<int>(mid - back) >= 0; mid--) {
121  Elem* e = &array_[mid & kMask];
122  uint8_t s = e->state.load(std::memory_order_relaxed);
123  if (n == 0) {
124  if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) continue;
125  start = mid;
126  } else {
127  // Note: no need to store temporal kBusy, we exclusively own these
128  // elements.
130  }
131  result->push_back(std::move(e->w));
132  e->state.store(kEmpty, std::memory_order_release);
133  n++;
134  }
135  if (n != 0) back_.store(start + 1 + (kSize << 1), std::memory_order_relaxed);
136  return n;
137  }
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
void start(const unsigned &i)
(Re-)start i-th timer
Definition: oomph_utilities.cc:243

References Eigen::RunQueue< Work, kSize >::array_, Eigen::RunQueue< Work, kSize >::back_, e(), eigen_plain_assert, Eigen::RunQueue< Work, kSize >::Empty(), Eigen::RunQueue< Work, kSize >::kBusy, Eigen::RunQueue< Work, kSize >::kEmpty, Eigen::RunQueue< Work, kSize >::kMask, Eigen::RunQueue< Work, kSize >::kReady, Eigen::RunQueue< Work, kSize >::mutex_, n, s, size, Eigen::RunQueue< Work, kSize >::Size(), and oomph::CumulativeTimings::start().

◆ PopFront()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PopFront ( )
inline
68  {
69  unsigned front = front_.load(std::memory_order_relaxed);
70  Elem* e = &array_[(front - 1) & kMask];
71  uint8_t s = e->state.load(std::memory_order_relaxed);
72  if (s != kReady || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return Work();
73  Work w = std::move(e->w);
74  e->state.store(kEmpty, std::memory_order_release);
75  front = ((front - 1) & kMask2) | (front & ~kMask2);
76  front_.store(front, std::memory_order_relaxed);
77  return w;
78  }

References Eigen::RunQueue< Work, kSize >::array_, e(), Eigen::RunQueue< Work, kSize >::front_, Eigen::RunQueue< Work, kSize >::kBusy, Eigen::RunQueue< Work, kSize >::kEmpty, Eigen::RunQueue< Work, kSize >::kMask, Eigen::RunQueue< Work, kSize >::kMask2, Eigen::RunQueue< Work, kSize >::kReady, s, and w.

Referenced by Eigen::RunQueue< Work, kSize >::Flush().

◆ PushBack()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PushBack ( Work  w)
inline
82  {
83  EIGEN_MUTEX_LOCK lock(mutex_);
84  unsigned back = back_.load(std::memory_order_relaxed);
85  Elem* e = &array_[(back - 1) & kMask];
86  uint8_t s = e->state.load(std::memory_order_relaxed);
87  if (s != kEmpty || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return w;
88  back = ((back - 1) & kMask2) | (back & ~kMask2);
89  back_.store(back, std::memory_order_relaxed);
90  e->w = std::move(w);
91  e->state.store(kReady, std::memory_order_release);
92  return Work();
93  }

References Eigen::RunQueue< Work, kSize >::array_, Eigen::RunQueue< Work, kSize >::back_, e(), Eigen::RunQueue< Work, kSize >::kBusy, Eigen::RunQueue< Work, kSize >::kEmpty, Eigen::RunQueue< Work, kSize >::kMask, Eigen::RunQueue< Work, kSize >::kMask2, Eigen::RunQueue< Work, kSize >::kReady, Eigen::RunQueue< Work, kSize >::mutex_, s, and w.

◆ PushFront()

template<typename Work , unsigned kSize>
Work Eigen::RunQueue< Work, kSize >::PushFront ( Work  w)
inline
55  {
56  unsigned front = front_.load(std::memory_order_relaxed);
57  Elem* e = &array_[front & kMask];
58  uint8_t s = e->state.load(std::memory_order_relaxed);
59  if (s != kEmpty || !e->state.compare_exchange_strong(s, kBusy, std::memory_order_acquire)) return w;
60  front_.store(front + 1 + (kSize << 1), std::memory_order_relaxed);
61  e->w = std::move(w);
62  e->state.store(kReady, std::memory_order_release);
63  return Work();
64  }

References Eigen::RunQueue< Work, kSize >::array_, e(), Eigen::RunQueue< Work, kSize >::front_, Eigen::RunQueue< Work, kSize >::kBusy, Eigen::RunQueue< Work, kSize >::kEmpty, Eigen::RunQueue< Work, kSize >::kMask, Eigen::RunQueue< Work, kSize >::kReady, s, and w.

◆ Size()

template<typename Work , unsigned kSize>
unsigned Eigen::RunQueue< Work, kSize >::Size ( ) const
inline
141 { return SizeOrNotEmpty<true>(); }

Referenced by Eigen::RunQueue< Work, kSize >::PopBackHalf(), and Eigen::RunQueue< Work, kSize >::~RunQueue().

◆ SizeOrNotEmpty()

template<typename Work , unsigned kSize>
template<bool NeedSizeEstimate>
unsigned Eigen::RunQueue< Work, kSize >::SizeOrNotEmpty ( ) const
inlineprivate
186  {
187  // Emptiness plays critical role in thread pool blocking. So we go to great
188  // effort to not produce false positives (claim non-empty queue as empty).
189  unsigned front = front_.load(std::memory_order_acquire);
190  for (;;) {
191  // Capture a consistent snapshot of front/tail.
192  unsigned back = back_.load(std::memory_order_acquire);
193  unsigned front1 = front_.load(std::memory_order_relaxed);
194  if (front != front1) {
195  front = front1;
196  std::atomic_thread_fence(std::memory_order_acquire);
197  continue;
198  }
199  if (NeedSizeEstimate) {
200  return CalculateSize(front, back);
201  } else {
202  // This value will be 0 if the queue is empty, and undefined otherwise.
203  unsigned maybe_zero = ((front ^ back) & kMask2);
204  // Queue size estimate must agree with maybe zero check on the queue
205  // empty/non-empty state.
206  eigen_assert((CalculateSize(front, back) == 0) == (maybe_zero == 0));
207  return maybe_zero;
208  }
209  }
210  }
#define eigen_assert(x)
Definition: Macros.h:910
EIGEN_ALWAYS_INLINE unsigned CalculateSize(unsigned front, unsigned back) const
Definition: RunQueue.h:212

References Eigen::RunQueue< Work, kSize >::back_, Eigen::RunQueue< Work, kSize >::CalculateSize(), eigen_assert, Eigen::RunQueue< Work, kSize >::front_, and Eigen::RunQueue< Work, kSize >::kMask2.

Member Data Documentation

◆ array_

◆ back_

◆ front_

◆ kMask

◆ kMask2

◆ mutex_

template<typename Work , unsigned kSize>
EIGEN_MUTEX Eigen::RunQueue< Work, kSize >::mutex_
private

The documentation for this class was generated from the following file: