24
24
#include < thread>
25
25
#include < vector>
26
26
27
- #include " numeric.h"
28
27
#include " util.h"
29
28
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
+
30
38
template <typename T>
31
39
void looper_int_fetch_add (T *aint, int model) {
32
40
static constexpr T val = V >> right_shift<T>();
@@ -167,14 +175,41 @@ void test_int_fetch_xor() {
167
175
}
168
176
}
169
177
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
+
170
205
template <typename T>
171
206
void test_int_xchg () {
172
207
static constexpr T val = V >> right_shift<T>();
173
208
std::vector<std::thread> pool;
174
209
for (int model : atomic_exchange_models) {
175
210
T aint = 0 ;
176
211
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);
178
213
for (int n = 0 ; n < kThreads ; ++n)
179
214
pool[n].join ();
180
215
pool.clear ();
@@ -183,7 +218,6 @@ void test_int_xchg() {
183
218
}
184
219
}
185
220
186
- // See numeric.h for an explanation of numeric xchg tests.
187
221
template <typename T>
188
222
void looper_int_xchg_n (T *aint, int model) {
189
223
static constexpr T val = V >> right_shift<T>();
@@ -213,6 +247,19 @@ void test_int_xchg_n() {
213
247
}
214
248
}
215
249
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
+
216
263
template <typename T>
217
264
void test_int_cmpxchg () {
218
265
static constexpr T val = V >> right_shift<T>();
@@ -221,7 +268,7 @@ void test_int_cmpxchg() {
221
268
for (int fail_model : atomic_compare_exchange_models) {
222
269
T aint = 0 ;
223
270
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,
225
272
fail_model);
226
273
for (int n = 0 ; n < kThreads ; ++n) pool[n].join ();
227
274
pool.clear ();
@@ -231,7 +278,6 @@ void test_int_cmpxchg() {
231
278
}
232
279
}
233
280
234
- // See numeric.h for an explanation of numeric cmpxchg tests.
235
281
template <typename T>
236
282
void looper_int_cmpxchg_n (T *aint, int success_model, int fail_model) {
237
283
static constexpr T val = V >> right_shift<T>();
@@ -298,8 +344,6 @@ void test_aligned_int() {
298
344
}
299
345
300
346
int main () {
301
- std::cout << kThreads << " threads; " << kIterations
302
- << " iterations each; total of " << kExpected << " \n " ;
303
347
test_aligned_int ();
304
348
std::cout << " PASSED\n " ;
305
349
}
0 commit comments