2424#include < thread>
2525#include < vector>
2626
27- #include " numeric.h"
2827#include " util.h"
2928
29+ // V >> 56 = 66, so to prevent 32-bit overflow, kExpected must be less than
30+ // 2^31 / 66 = 32 x 10^6.
31+ #ifdef SMALL_PROBLEM_SIZE
32+ static constexpr int kIterations = 1'000'000 ;
33+ #else
34+ static constexpr int kIterations = 3'000'000 ;
35+ #endif
36+ static constexpr int kExpected = kThreads * kIterations ;
37+
3038template <typename T>
3139void looper_int_fetch_add (T *aint, int model) {
3240 static constexpr T val = V >> right_shift<T>();
@@ -167,14 +175,41 @@ void test_int_fetch_xor() {
167175 }
168176}
169177
178+ // The xchg tests work as follows:
179+ //
180+ // Each thread increments a local copy of the shared variable, and exchanges it
181+ // with the shared value. Most of the time, the value moved from shared -> local
182+ // is one less than the value moved from local -> shared. Other times, the
183+ // difference is much bigger (or smaller). When this occurs, the thread
184+ // accumulates the difference in a local error variable. Upon completion, the
185+ // thread subtracts the error from the shared value, all at once.
186+ //
187+ // Like many tests, this test increments by more than 1 -- specifically, a
188+ // number that scales with the width of the type is picked.
189+ //
190+ template <typename T>
191+ void looper_int_xchg (T *aint, int model) {
192+ static constexpr T val = V >> right_shift<T>();
193+ __int128_t error = 0 ;
194+ T next = *aint + val;
195+ T result;
196+ for (int n = 0 ; n < kIterations ; ++n) {
197+ __atomic_exchange (aint, &next, &result, model);
198+ error +=
199+ static_cast <__int128_t >(next) - static_cast <__int128_t >(result + val);
200+ next = result + val;
201+ }
202+ __atomic_fetch_sub (aint, static_cast <T>(error), model);
203+ }
204+
170205template <typename T>
171206void test_int_xchg () {
172207 static constexpr T val = V >> right_shift<T>();
173208 std::vector<std::thread> pool;
174209 for (int model : atomic_exchange_models) {
175210 T aint = 0 ;
176211 for (int n = 0 ; n < kThreads ; ++n)
177- pool.emplace_back (looper_numeric_xchg_atomic <T>, &aint, model);
212+ pool.emplace_back (looper_int_xchg <T>, &aint, model);
178213 for (int n = 0 ; n < kThreads ; ++n)
179214 pool[n].join ();
180215 pool.clear ();
@@ -183,7 +218,6 @@ void test_int_xchg() {
183218 }
184219}
185220
186- // See numeric.h for an explanation of numeric xchg tests.
187221template <typename T>
188222void looper_int_xchg_n (T *aint, int model) {
189223 static constexpr T val = V >> right_shift<T>();
@@ -213,6 +247,19 @@ void test_int_xchg_n() {
213247 }
214248}
215249
250+ // The cmpxchg tests act similar to fetch_add tests.
251+ template <typename T>
252+ void looper_int_cmpxchg (T *aint, int success_model, int fail_model) {
253+ static constexpr T val = V >> right_shift<T>();
254+ for (int n = 0 ; n < kIterations ; ++n) {
255+ T desired, expected = 0 ;
256+ do {
257+ desired = expected + val;
258+ } while (!__atomic_compare_exchange (aint, &expected, &desired, true ,
259+ success_model, fail_model));
260+ }
261+ }
262+
216263template <typename T>
217264void test_int_cmpxchg () {
218265 static constexpr T val = V >> right_shift<T>();
@@ -221,7 +268,7 @@ void test_int_cmpxchg() {
221268 for (int fail_model : atomic_compare_exchange_models) {
222269 T aint = 0 ;
223270 for (int n = 0 ; n < kThreads ; ++n)
224- pool.emplace_back (looper_numeric_cmpxchg <T>, &aint, success_model,
271+ pool.emplace_back (looper_int_cmpxchg <T>, &aint, success_model,
225272 fail_model);
226273 for (int n = 0 ; n < kThreads ; ++n) pool[n].join ();
227274 pool.clear ();
@@ -231,7 +278,6 @@ void test_int_cmpxchg() {
231278 }
232279}
233280
234- // See numeric.h for an explanation of numeric cmpxchg tests.
235281template <typename T>
236282void looper_int_cmpxchg_n (T *aint, int success_model, int fail_model) {
237283 static constexpr T val = V >> right_shift<T>();
@@ -298,8 +344,6 @@ void test_aligned_int() {
298344}
299345
300346int main () {
301- std::cout << kThreads << " threads; " << kIterations
302- << " iterations each; total of " << kExpected << " \n " ;
303347 test_aligned_int ();
304348 std::cout << " PASSED\n " ;
305349}
0 commit comments