MADNESS  0.10.1
atomicint.h
Go to the documentation of this file.
1 /*
2  This file is part of MADNESS.
3 
4  Copyright (C) 2007,2010 Oak Ridge National Laboratory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20  For more information please contact:
21 
22  Robert J. Harrison
23  Oak Ridge National Laboratory
24  One Bethel Valley Road
25  P.O. Box 2008, MS-6367
26 
27  email: harrisonrj@ornl.gov
28  tel: 865-241-3937
29  fax: 865-572-0680
30 */
31 
32 #ifndef MADNESS_WORLD_ATOMICINT_H__INCLUDED
33 #define MADNESS_WORLD_ATOMICINT_H__INCLUDED
34 
35 /**
36  \file atomicint.h
37  \brief Implements \c AtomicInt.
38  \ingroup atomics
39 */
40 
41 #include <madness/madness_config.h>
42 
43 /// \addtogroup atomics
44 /// @{
45 
46 /* Jeff: I suppose there is a cleaner way to do this with preprocess arithmetic,
47  * but I do not think it matters. This code is clear enough. */
48 
49 #if defined(__GNUC__) && defined(__GNUC_MINOR__)
50 # if (__GNUC__ >= 5) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
51 # define MADNESS_GCC_48_OR_HIGHER
52 # endif
53 #endif
54 
55 #if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
56 # if (__clang_major__ >= 4) || (__clang_major__ == 3 && __clang_minor__ >= 3)
57 # define MADNESS_CLANG_33_OR_HIGHER
58 # endif
59 #endif
60 
61 #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300)
62 #define MADNESS_ICC_130_OR_HIGHER
63 #endif
64 
65 /* Jeff: This needs to move into config.h and have an associated configure test. */
66 /* Jeff: Nick does not want this used on Blue Gene/Q, so we will not allow it
67  * even if other tests indicate that it should work. */
68 #if !defined(__bgq__) && (__cplusplus >= 201103L)
69 # if defined(MADNESS_GCC_48_OR_HIGHER) || defined(MADNESS_CLANG_33_OR_HIGHER)
70 # define HAVE_CXX_ATOMICS
71 # endif
72 #endif
73 
74 #ifdef MADNESS_GCC_48_OR_HIGHER
75 #undef MADNESS_GCC_48_OR_HIGHER
76 #endif
77 
78 #ifdef MADNESS_ICC_130_OR_HIGHER
79 #undef MADNESS_ICC_130_OR_HIGHER
80 #endif
81 
82 #ifdef MADNESS_CLANG_33_OR_HIGHER
83 #undef MADNESS_CLANG_33_OR_HIGHER
84 #endif
85 
86 #if defined(HAVE_CXX_ATOMICS)
87 # define MADATOMIC_USE_CXX
88 /* Jeff: It is odd that MADATOMIC_USE_GCC is tested before it is defined,
89  * at least in this file. Is this intentional? */
90 #elif defined(HAVE_IBMBGP) && !defined(MADATOMIC_USE_GCC)
91 # define MADATOMIC_USE_BGP
92 #elif defined(HAVE_IBMBGQ)
93 # define MADATOMIC_USE_BGQ
94 #elif defined(USE_X86_32_ASM) || defined(USE_X86_64_ASM) || defined(X86_64) || defined(X86_32)
95 # define MADATOMIC_USE_X86_ASM
96 #else
97 # define MADATOMIC_USE_GCC
98 #endif
99 
100 #if defined(MADATOMIC_USE_CXX)
101 # include <atomic>
102 #elif defined(MADATOMIC_USE_BGP)
103 # include <bpcore/bgp_atomic_ops.h>
104 #elif defined (MADATOMIC_USE_BGQ)
105 # include "bgq_atomics.h"
106 #elif defined(MADATOMIC_USE_AIX)
107 # include <sys/atomic_op.h>
108 #elif defined(MADATOMIC_USE_GCC)
109 # ifdef GCC_ATOMICS_IN_BITS
110 # include <bits/atomicity.h>
111 # else
112 # include <ext/atomicity.h>
113 # endif
114 #endif
115 
116 namespace madness {
117 
118  /// \brief An integer with atomic set, get, read+increment, read+decrement,
119  /// and decrement+test operations.
120 
121  /// Only the default constructor is available and it does \emph not
122  /// initialize the variable.
123  ///
124  /// Consciously modeled after the TBB API to prepare for switching to it.
125  /// \todo Should we actually switch to the TBB version?
126  class AtomicInt {
127  private:
128 
129  /// Storage type for the atomic integer.
130 #if defined(MADATOMIC_USE_CXX)
131  typedef std::atomic_int atomic_int;
132 #elif defined(MADATOMIC_USE_BGP)
133  typedef _BGP_Atomic atomic_int;
134 #elif defined(MADATOMIC_USE_BGQ)
135  /* It might be prudent to add the aligned/padding attribute
136  * here, for performance, similar to what _BGP_Atomic does. */
137  typedef volatile int atomic_int;
138 #else
139  typedef volatile int atomic_int;
140 #endif
141  atomic_int value; ///< The atomic integer.
142 
143  /// \todo Brief description needed.
144 
145  /// \todo Descriptions needed.
146  /// \param[in] i Description needed.
147  /// \return Description needed.
148  inline int exchange_and_add(int i) {
149 #if defined(MADATOMIC_USE_CXX)
150  return value.fetch_add(i,std::memory_order_seq_cst);
151 #elif defined(MADATOMIC_USE_GCC)
152  return __gnu_cxx::__exchange_and_add(&value,i);
153 #elif defined(MADATOMIC_USE_X86_ASM)
154  __asm__ __volatile__("lock; xaddl %0,%1" :"=r"(i) : "m"(value), "0"(i));
155  return i;
156 #elif defined(MADATOMIC_USE_AIX)
157  return fetch_and_add(&value,i);
158 #elif defined(MADATOMIC_USE_BGP)
159  return _bgp_fetch_and_add(&value,i);
160 #elif defined(MADATOMIC_USE_BGQ)
161  return FetchAndAddSigned32(&value,i);
162 #else
163 # error ... atomic exchange_and_add operator must be implemented for this platform;
164 #endif
165  }
166 
167  public:
168  /// \brief Returns the value of the counter with fence, ensuring
169  /// subsequent operations are not moved before the load.
170  operator int() const volatile {
171  /* Jeff moved the memory barrier inside of the architecture-specific blocks
172  * since it may be required to use a heavier hammer on some of them. */
173 #if defined(MADATOMIC_USE_CXX)
174  return value.load(std::memory_order_seq_cst);
175 #elif defined(MADATOMIC_USE_BGP)
176  int result = value.atom;
177  __asm__ __volatile__ ("" : : : "memory");
178  return result;
179 #elif defined (MADATOMIC_USE_BGQ)
180  int result = value;
181  __asm__ __volatile__ ("" : : : "memory");
182  return result;
183 #else
184  int result = value;
185  // BARRIER to stop instructions migrating up
186  __asm__ __volatile__ ("" : : : "memory");
187  return result;
188 #endif
189  }
190 
191  /// Sets the value of the counter, with a fence ensuring that preceding
192  /// operations are not moved after the store.
193 
194  /// \todo Descriptions needed.
195  /// \param[in] other Description needed.
196  /// \return Description needed.
197  int operator=(int other) {
198  /* Jeff moved the memory barrier inside of the architecture-specific blocks
199  * since it may be required to use a heavier hammer on some of them. */
200 #if defined(MADATOMIC_USE_CXX)
201  value.store(other,std::memory_order_seq_cst);
202 #elif defined(MADATOMIC_USE_BGP)
203  // BARRIER to stop instructions migrating down
204  __asm__ __volatile__ ("" : : : "memory");
205  value.atom = other;
206 #elif defined (MADATOMIC_USE_BGQ)
207  __asm__ __volatile__ ("" : : : "memory");
208  value = other;
209 #else
210  __asm__ __volatile__ ("" : : : "memory");
211  value = other;
212 #endif
213  return other;
214  }
215 
216  /// \brief Sets the value of the counter, with fences to ensure that
217  /// operations are not moved to either side of the load+store.
218 
219  /// \param[in] other The value to set to.
220  /// \return This \c AtomicInt.
221  AtomicInt& operator=(const AtomicInt& other) {
222  *this = int(other);
223  return *this;
224  }
225 
226  /// Decrements the counter and returns the original value.
227 
228  /// \return The original value.
229  int operator--(int) {
230 #if defined(MADATOMIC_USE_CXX)
231  return value--;
232 #else
233  return exchange_and_add(-1);
234 #endif
235  }
236 
237  /// Decrements the counter and returns the decremented value.
238 
239  /// \return The decremented value.
240  int operator--() {
241 #if defined(MADATOMIC_USE_CXX)
242  return --value;
243 #else
244  return exchange_and_add(-1) - 1;
245 #endif
246  }
247 
248  /// Increments the counter and returns the original value.
249 
250  /// \return The original value.
251  int operator++(int) {
252 #if defined(MADATOMIC_USE_CXX)
253  return value++;
254 #else
255  return exchange_and_add(1);
256 #endif
257  }
258 
259  /// Increments the counter and returns the incremented value.
260 
261  /// \return The incremented value.
262  int operator++() {
263 #if defined(MADATOMIC_USE_CXX)
264  return ++value;
265 #else
266  return exchange_and_add(1) + 1;
267 #endif
268  }
269 
270  /// Add \c value and return the new value.
271 
272  /// \param[in] inc The value to be added.
273  /// \return The new value.
274  int operator+=(const int inc) {
275 #if defined(MADATOMIC_USE_CXX)
276  return (value.fetch_add(inc, std::memory_order_seq_cst) + inc);
277 #else
278  return exchange_and_add(inc) + inc;
279 #endif
280  }
281 
282  /// Subtract \c dec and return the new value.
283 
284  /// \param[in] dec The value to be subtracted.
285  /// \return The new value.
286  int operator-=(const int dec) {
287 #if defined(MADATOMIC_USE_CXX)
288  return (value.fetch_sub(dec, std::memory_order_seq_cst) - dec);
289 #else
290  return exchange_and_add(-dec) - dec;
291 #endif
292  }
293 
294  /// Decrements the counter and returns true if the new value is zero,
295 
296  /// \return True if the decremented value is 0; false otherwise.
297  bool dec_and_test() {
298  return ((*this)-- == 1);
299  }
300 
301 #ifdef ATOMICINT_CAS
302  /// Compare and swap.
303 
304  /// If `value == compare` then set `value = newval`.
305  /// \param[in] compare The value to compare against.
306  /// \param[in] newval The new value if the comparison is true.
307  /// \return The original value.
308  inline int compare_and_swap(int compare, int newval) {
309 #if defined(MADATOMIC_USE_CXX)
310 #warning The C++11 implementation of compare-and-swap has never been tested.
311  std::bool swapped = value.compare_exchange_strong_explicit(&compare, newval,
312  std::memory_order_seq_cst,
313  std::memory_order_seq_cst);
314  /* We must return the original value, which is not the return argument above.
315  * If swapped=true, then obj was expected before the call, so we return that.
316  * If swapped=false, then obj is unchanged, so we can just return that. */
317  return (swapped ? compare : value);
318 #elif defined(MADATOMIC_USE_GCC)
319  return __sync_val_compare_and_swap(&value, compare, newval);
320 #elif defined(MADATOMIC_USE_BGP)
321  return _bgp_compare_and_swap(&value, compare, newval);
322 #elif defined(MADATOMIC_USE_BGQ)
323  return CompareAndSwapSigned32(&value, compare, newval);
324 #else
325 #error ... atomic exchange_and_add operator must be implemented for this platform;
326 #endif
327  }
328 #endif
329 
330  }; // class AtomicInt
331 
332 }
333 
334 /// @}
335 
336 #endif // MADNESS_WORLD_ATOMICINT_H__INCLUDED
An integer with atomic set, get, read+increment, read+decrement, and decrement+test operations.
Definition: atomicint.h:126
int operator--()
Decrements the counter and returns the decremented value.
Definition: atomicint.h:240
atomic_int value
The atomic integer.
Definition: atomicint.h:141
int operator-=(const int dec)
Subtract dec and return the new value.
Definition: atomicint.h:286
volatile int atomic_int
Storage type for the atomic integer.
Definition: atomicint.h:139
AtomicInt & operator=(const AtomicInt &other)
Sets the value of the counter, with fences to ensure that operations are not moved to either side of ...
Definition: atomicint.h:221
int operator++()
Increments the counter and returns the incremented value.
Definition: atomicint.h:262
int operator=(int other)
Definition: atomicint.h:197
int exchange_and_add(int i)
Definition: atomicint.h:148
int operator+=(const int inc)
Add value and return the new value.
Definition: atomicint.h:274
bool dec_and_test()
Decrements the counter and returns true if the new value is zero,.
Definition: atomicint.h:297
int operator--(int)
Decrements the counter and returns the original value.
Definition: atomicint.h:229
int operator++(int)
Increments the counter and returns the original value.
Definition: atomicint.h:251
Macros and tools pertaining to the configuration of MADNESS.
File holds all helper structures necessary for the CC_Operator and CC2 class.
Definition: DFParameters.h:10
int compare(World &world, functionT test, functionT exact, const char *str)
Definition: testdiff1D.cc:19