Skip to content

Commit dd84b71

Browse files
committed
Make kExpected file-specific, rewrite float tests to avoid epsilon.
1 parent 46300e0 commit dd84b71

11 files changed

+122
-61
lines changed

SingleSource/UnitTests/Atomic/big_test.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,14 @@
2323

2424
#include "util.h"
2525

26+
// V >> 56 = 66, so to prevent 32-bit overflow, kExpected must be less than
27+
// 2^31 / 66 = 32 x 10^6.
28+
#ifdef SMALL_PROBLEM_SIZE
29+
static constexpr int kIterations = 1'000'000;
30+
#else
31+
static constexpr int kIterations = 3'000'000;
32+
#endif
33+
static constexpr int kExpected = kThreads * kIterations;
2634
static constexpr int kBigSize = 10;
2735
struct big_t {
2836
int v[kBigSize];
@@ -44,7 +52,6 @@ void looper_big_cmpxchg(big_t *abig, int success_model, int fail_model) {
4452

4553
void test_big_cmpxchg() {
4654
std::vector<std::thread> pool;
47-
4855
for (int success_model : atomic_compare_exchange_models) {
4956
for (int fail_model : atomic_compare_exchange_models) {
5057
big_t abig = {};
@@ -66,9 +73,6 @@ void test_big() {
6673
}
6774

6875
int main() {
69-
std::cout << kThreads << " threads; "
70-
<< kIterations << " iterations each; total of "
71-
<< kExpected << "\n";
7276
test_big();
7377
std::cout << "PASSED\n";
7478
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
10 threads; 1000000 iterations each; total of 10000000
21
Testing big
32
PASSED
43
exit 0

SingleSource/UnitTests/Atomic/float_test.cpp

+38-20
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// This file tests atomic operations on floating point types with aligned
1010
// memory addresses.
1111
//
12-
// The types tested are: float, double.
12+
// The types tested are: float, double, float128.
1313
// The ops tested are: xchg, cmpxchg.
1414
//
1515
// Please read the README before contributing.
@@ -22,47 +22,68 @@
2222
#include <thread>
2323
#include <vector>
2424

25-
#include "numeric.h"
2625
#include "util.h"
2726

28-
// See numeric.h for an explanation of numeric xchg tests.
27+
// There are 23-bits in the mantissa of a single-precision float.
28+
// Therefore, kExpected cannot exceed 2^24.
29+
static constexpr int kIterations = 1'500'000;
30+
static constexpr int kExpected = kThreads * kIterations;
31+
32+
// See int_aligned_test.cc for an explanation of xchg tests.
33+
template <typename T>
34+
void looper_float_scalar_xchg(T *afloat, int model) {
35+
__int128_t error = 0;
36+
T next = *afloat + 1;
37+
T result;
38+
for (int n = 0; n < kIterations; ++n) {
39+
__atomic_exchange(afloat, &next, &result, model);
40+
error +=
41+
static_cast<__int128_t>(next) - static_cast<__int128_t>(result + 1);
42+
next = result + 1;
43+
}
44+
__atomic_fetch_sub(afloat, static_cast<T>(error), model);
45+
}
46+
2947
template <typename T>
3048
void test_float_scalar_xchg() {
31-
static constexpr T val = V >> right_shift<T>();
32-
static constexpr T expected = val * kExpected;
3349
std::vector<std::thread> pool;
34-
3550
for (int model : atomic_exchange_models) {
3651
T afloat = 0;
3752
for (int n = 0; n < kThreads; ++n)
38-
pool.emplace_back(looper_numeric_xchg_atomic<T>, &afloat, model);
53+
pool.emplace_back(looper_float_scalar_xchg<T>, &afloat, model);
3954
for (int n = 0; n < kThreads; ++n)
4055
pool[n].join();
4156
pool.clear();
42-
if (afloat < expected * (1 - kEpsilon) ||
43-
afloat > expected * (1 + kEpsilon))
57+
if (afloat != kExpected)
4458
fail();
4559
}
4660
}
4761

48-
// See numeric.h for an explanation of numeric cmpxchg tests.
62+
// See int_aligned_test.cc for an explanation of cmpxchg tests.
63+
template <typename T>
64+
void looper_float_scalar_cmpxchg(T *afloat, int success_model, int fail_model) {
65+
for (int n = 0; n < kIterations; ++n) {
66+
T desired, expected = 0;
67+
do {
68+
desired = expected + 1;
69+
} while (!__atomic_compare_exchange(afloat, &expected, &desired, true,
70+
success_model, fail_model));
71+
}
72+
}
73+
4974
template <typename T>
5075
void test_float_scalar_cmpxchg() {
51-
static constexpr T val = V >> right_shift<T>();
52-
static constexpr T expected = val * kExpected;
5376
std::vector<std::thread> pool;
54-
5577
for (int success_model : atomic_compare_exchange_models) {
5678
for (int fail_model : atomic_compare_exchange_models) {
5779
T afloat = 0;
5880
for (int n = 0; n < kThreads; ++n)
59-
pool.emplace_back(looper_numeric_cmpxchg<T>, &afloat, success_model,
60-
fail_model);
81+
pool.emplace_back(looper_float_scalar_cmpxchg<T>, &afloat,
82+
success_model, fail_model);
6183
for (int n = 0; n < kThreads; ++n)
6284
pool[n].join();
6385
pool.clear();
64-
if (afloat < expected * (1 - kEpsilon) ||
65-
afloat > expected * (1 + kEpsilon))
86+
if (afloat != kExpected)
6687
fail();
6788
}
6889
}
@@ -83,9 +104,6 @@ void test_floating_point() {
83104
}
84105

85106
int main() {
86-
std::cout << kThreads << " threads; "
87-
<< kIterations << " iterations each; total of "
88-
<< kExpected << "\n";
89107
test_floating_point();
90108
std::cout << "PASSED\n";
91109
}

SingleSource/UnitTests/Atomic/float_test.reference_output

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
10 threads; 1000000 iterations each; total of 10000000
21
Testing float
32
Testing double
43
Testing float128

SingleSource/UnitTests/Atomic/int_aligned_test.cpp

+51-7
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,17 @@
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+
3038
template <typename T>
3139
void 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+
170205
template <typename T>
171206
void 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.
187221
template <typename T>
188222
void 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+
216263
template <typename T>
217264
void 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.
235281
template <typename T>
236282
void 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

300346
int main() {
301-
std::cout << kThreads << " threads; " << kIterations
302-
<< " iterations each; total of " << kExpected << "\n";
303347
test_aligned_int();
304348
std::cout << "PASSED\n";
305349
}

SingleSource/UnitTests/Atomic/int_aligned_test.reference_output

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
10 threads; 1000000 iterations each; total of 10000000
21
Testing aligned uint32_t
32
Testing aligned uint64_t
43
Testing aligned int32_t

SingleSource/UnitTests/Atomic/int_misaligned_test.cpp

+13-8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@
2727

2828
#include "util.h"
2929

30+
#ifdef SMALL_PROBLEM_SIZE
31+
static constexpr int kIterations = 50'000;
32+
#else
33+
static constexpr int kIterations = 500'000;
34+
#endif
35+
static constexpr int kExpected = kThreads * kIterations;
36+
3037
template <typename T>
3138
struct __attribute__((packed)) misaligned {
3239
char byte;
@@ -179,9 +186,9 @@ void test_int_misaligned_fetch_xor() {
179186
}
180187
}
181188

182-
// See numeric.h for an explanation of numeric xchg tests.
189+
// See int_aligned_test.cc for an explanation of xchg tests.
183190
template <typename T>
184-
void looper_int_misaligned_xchg_atomic(misaligned<T> &astruct, int model) {
191+
void looper_int_misaligned_xchg(misaligned<T> &astruct, int model) {
185192
static constexpr T val = V >> right_shift<T>();
186193
__int128_t error = 0;
187194
T next = astruct.data + val;
@@ -203,7 +210,7 @@ void test_int_misaligned_xchg() {
203210
for (int model : atomic_exchange_models) {
204211
astruct.data = 0;
205212
for (int n = 0; n < kThreads; ++n)
206-
pool.emplace_back(looper_int_misaligned_xchg_atomic<T>, std::ref(astruct),
213+
pool.emplace_back(looper_int_misaligned_xchg<T>, std::ref(astruct),
207214
model);
208215
for (int n = 0; n < kThreads; ++n)
209216
pool[n].join();
@@ -213,7 +220,7 @@ void test_int_misaligned_xchg() {
213220
}
214221
}
215222

216-
// See numeric.h for an explanation of numeric xchg tests.
223+
// See int_aligned_test.cc for an explanation of xchg tests.
217224
template <typename T>
218225
void looper_int_misaligned_xchg_n(misaligned<T> &astruct, int model) {
219226
static constexpr T val = V >> right_shift<T>();
@@ -246,7 +253,7 @@ void test_int_misaligned_xchg_n() {
246253
}
247254
}
248255

249-
// See numeric.h for an explanation of numeric cmpxchg tests.
256+
// See int_aligned_test.cc for an explanation of cmpxchg tests.
250257
template <typename T>
251258
void looper_int_misaligned_cmpxchg(misaligned<T> &astruct, int success_model,
252259
int fail_model) {
@@ -280,7 +287,7 @@ void test_int_misaligned_cmpxchg() {
280287
}
281288
}
282289

283-
// See numeric.h for an explanation of numeric cmpxchg tests.
290+
// See int_aligned_test.cc for an explanation of cmpxchg tests.
284291
template <typename T>
285292
void looper_int_misaligned_cmpxchg_n(misaligned<T> &astruct, int success_model,
286293
int fail_model) {
@@ -350,8 +357,6 @@ void test_misaligned_int() {
350357
}
351358

352359
int main() {
353-
std::cout << kThreads << " threads; " << kIterations
354-
<< " iterations each; total of " << kExpected << "\n";
355360
test_misaligned_int();
356361
std::cout << "PASSED\n";
357362
}

SingleSource/UnitTests/Atomic/int_misaligned_test.reference_output

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
10 threads; 1000000 iterations each; total of 10000000
21
Testing misaligned uint32_t
32
Testing misaligned uint64_t
43
Testing misaligned int32_t

0 commit comments

Comments
 (0)