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
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
116namespace 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.
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.
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.
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.
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
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
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--(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.
Namespace for all elements and tools of MADNESS.
Definition DFParameters.h:10
int compare(World &world, functionT test, functionT exact, const char *str)
Definition testdiff1D.cc:19