Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* crosstest.py --test=test_sync_atomic.cpp --crosstest-bitcode=0 \ | |
| 2 --driver=test_sync_atomic_main.cpp --prefix=Subzero_ \ | |
| 3 --output=test_sync_atomic */ | |
| 4 | |
| 5 #include <pthread.h> | |
| 6 #include <stdint.h> | |
|
JF
2014/07/13 19:56:12
<cstdint>
jvoung (off chromium)
2014/07/14 16:20:30
The tests are currently not compiling w/ -std= any
| |
| 7 | |
| 8 #include <cstdlib> | |
| 9 #include <iostream> | |
| 10 | |
| 11 // Include test_sync_atomic.h twice - once normally, and once within the | |
| 12 // Subzero_ namespace, corresponding to the llc and Subzero translated | |
| 13 // object files, respectively. | |
| 14 #include "test_sync_atomic.h" | |
| 15 namespace Subzero_ { | |
| 16 #include "test_sync_atomic.h" | |
| 17 } | |
| 18 | |
| 19 volatile uint64_t Values[] = { | |
| 20 0, 1, 0x7e, | |
| 21 0x7f, 0x80, 0x81, | |
| 22 0xfe, 0xff, 0x7ffe, | |
| 23 0x7fff, 0x8000, 0x8001, | |
| 24 0xfffe, 0xffff, | |
| 25 0x007fffff /*Max subnormal + */, | |
| 26 0x00800000 /*Min+ */, 0x7f7fffff /*Max+ */, | |
| 27 0x7f800000 /*+Inf*/, 0xff800000 /*-Inf*/, | |
| 28 0x7fa00000 /*SNaN*/, 0x7fc00000 /*QNaN*/, | |
| 29 0x7ffffffe, 0x7fffffff, 0x80000000, | |
| 30 0x80000001, 0xfffffffe, 0xffffffff, | |
| 31 0x100000000ll, 0x100000001ll, | |
| 32 0x000fffffffffffffll /*Max subnormal + */, | |
| 33 0x0010000000000000ll /*Min+ */, | |
| 34 0x7fefffffffffffffll /*Max+ */, | |
| 35 0x7ff0000000000000ll /*+Inf*/, | |
| 36 0xfff0000000000000ll /*-Inf*/, | |
| 37 0x7ff0000000000001ll /*SNaN*/, | |
| 38 0x7ff8000000000000ll /*QNaN*/, | |
| 39 0x7ffffffffffffffell, 0x7fffffffffffffffll, 0x8000000000000000ll, | |
| 40 0x8000000000000001ll, 0xfffffffffffffffell, 0xffffffffffffffffll }; | |
| 41 | |
| 42 const static size_t NumValues = sizeof(Values) / sizeof(*Values); | |
| 43 | |
| 44 struct { | |
| 45 volatile uint8_t l8; | |
| 46 volatile uint16_t l16; | |
| 47 volatile uint32_t l32; | |
| 48 volatile uint64_t l64; | |
| 49 } AtomicLocs; | |
| 50 | |
| 51 template <typename Type> | |
| 52 void testAtomicRMW(volatile Type *AtomicLoc, | |
| 53 size_t &TotalTests, size_t &Passes, size_t &Failures) { | |
| 54 typedef Type (*FuncType)(bool, volatile Type*, Type); | |
| 55 static struct { | |
| 56 const char *Name; | |
| 57 FuncType FuncLlc; | |
| 58 FuncType FuncSz; | |
| 59 } Funcs[] = { | |
| 60 #define X(inst) \ | |
| 61 { \ | |
| 62 STR(inst), test_##inst, Subzero_::test_##inst \ | |
| 63 }, \ | |
| 64 { \ | |
| 65 STR(inst) "_alloca", test_alloca_##inst, Subzero_::test_alloca_##inst \ | |
| 66 }, \ | |
| 67 { \ | |
| 68 STR(inst) "_const", test_const_##inst, Subzero_::test_const_##inst \ | |
| 69 }, | |
| 70 RMWOP_TABLE | |
| 71 #undef X | |
| 72 }; | |
| 73 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs); | |
| 74 | |
| 75 for (size_t f = 0; f < NumFuncs; ++f) { | |
| 76 for (size_t i = 0; i < NumValues; ++i) { | |
| 77 Type Value1 = static_cast<Type>(Values[i]); | |
| 78 for (size_t j = 0; j < NumValues; ++j) { | |
| 79 Type Value2 = static_cast<Type>(Values[j]); | |
| 80 for (size_t k = 0; k < 2; ++k) { | |
| 81 bool fetch_first = k; | |
| 82 ++TotalTests; | |
| 83 *AtomicLoc = Value1; | |
| 84 Type ResultSz1 = Funcs[f].FuncSz( | |
| 85 fetch_first, AtomicLoc, Value2); | |
| 86 Type ResultSz2 = *AtomicLoc; | |
| 87 *AtomicLoc = Value1; | |
| 88 Type ResultLlc1 = Funcs[f].FuncLlc( | |
| 89 fetch_first, AtomicLoc, Value2); | |
| 90 Type ResultLlc2 = *AtomicLoc; | |
| 91 if (ResultSz1 == ResultLlc1 && ResultSz2 == ResultLlc2) { | |
| 92 ++Passes; | |
| 93 } else { | |
| 94 ++Failures; | |
| 95 std::cout << "test_" << Funcs[f].Name | |
| 96 << (8 * sizeof(Type)) << "(" | |
|
JF
2014/07/13 19:56:12
s/8/CHAR_BIT/
Here and 2 other places below.
jvoung (off chromium)
2014/07/14 16:20:30
Done.
| |
| 97 << static_cast<uint64_t>(Value1) << ", " | |
| 98 << static_cast<uint64_t>(Value2) | |
| 99 << "): sz1=" << static_cast<uint64_t>(ResultSz1) | |
| 100 << " llc1=" << static_cast<uint64_t>(ResultLlc1) | |
| 101 << " sz2=" << static_cast<uint64_t>(ResultSz2) | |
| 102 << " llc2=" << static_cast<uint64_t>(ResultLlc2) | |
| 103 << std::endl; | |
|
JF
2014/07/13 19:56:12
I'd just use '\n', since std::endl also leads to a
jvoung (off chromium)
2014/07/14 16:20:30
FWIW: this only prints when there is an error, so
| |
| 104 } | |
| 105 } | |
| 106 } | |
| 107 } | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 template <typename Type> | |
| 112 void testValCompareAndSwap(volatile Type *AtomicLoc, size_t &TotalTests, | |
| 113 size_t &Passes, size_t &Failures) { | |
| 114 for (size_t i = 0; i < NumValues; ++i) { | |
| 115 Type Value1 = static_cast<Type>(Values[i]); | |
| 116 for (size_t j = 0; j < NumValues; ++j) { | |
| 117 Type Value2 = static_cast<Type>(Values[j]); | |
| 118 for (size_t f = 0; f < 2; ++f) { | |
| 119 bool flip = f; | |
| 120 ++TotalTests; | |
| 121 *AtomicLoc = Value1; | |
| 122 Type ResultSz1 = Subzero_::test_val_cmp_swap( | |
| 123 AtomicLoc, flip ? Value2 : Value1, Value2); | |
| 124 Type ResultSz2 = *AtomicLoc; | |
| 125 *AtomicLoc = Value1; | |
| 126 Type ResultLlc1 = test_val_cmp_swap( | |
| 127 AtomicLoc, flip ? Value2 : Value1, Value2); | |
| 128 Type ResultLlc2 = *AtomicLoc; | |
| 129 if (ResultSz1 == ResultLlc1 && ResultSz2 == ResultLlc2) { | |
| 130 ++Passes; | |
| 131 } else { | |
| 132 ++Failures; | |
| 133 std::cout << "test_val_cmp_swap" << (8 * sizeof(Type)) << "(" | |
| 134 << static_cast<uint64_t>(Value1) << ", " | |
| 135 << static_cast<uint64_t>(Value2) | |
| 136 << "): sz1=" << static_cast<uint64_t>(ResultSz1) | |
| 137 << " llc1=" << static_cast<uint64_t>(ResultLlc1) | |
| 138 << " sz2=" << static_cast<uint64_t>(ResultSz2) | |
| 139 << " llc2=" << static_cast<uint64_t>(ResultLlc2) | |
| 140 << std::endl; | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 template <typename Type> | |
| 148 struct ThreadData { | |
| 149 Type (*FuncPtr)(bool, volatile Type*, Type); | |
| 150 bool Fetch; | |
| 151 volatile Type *Ptr; | |
| 152 Type Adjustment; | |
| 153 }; | |
| 154 | |
| 155 template <typename Type> | |
| 156 void *threadWrapper(void *Data) { | |
| 157 const size_t NumReps = 8000; | |
| 158 ThreadData<Type> *TData = reinterpret_cast<ThreadData<Type>*>(Data); | |
| 159 for (size_t i = 0; i < NumReps; ++i) { | |
| 160 (void)TData->FuncPtr(TData->Fetch, TData->Ptr, TData->Adjustment); | |
| 161 } | |
| 162 return NULL; | |
| 163 } | |
| 164 | |
| 165 template <typename Type> | |
| 166 void testAtomicRMWThreads(volatile Type *AtomicLoc, size_t &TotalTests, | |
| 167 size_t &Passes, size_t &Failures) { | |
| 168 typedef Type (*FuncType)(bool, volatile Type*, Type); | |
| 169 static struct { | |
| 170 const char *Name; | |
| 171 FuncType FuncLlc; | |
| 172 FuncType FuncSz; | |
| 173 } Funcs[] = { | |
| 174 #define X(inst) \ | |
| 175 { \ | |
| 176 STR(inst), test_##inst, Subzero_::test_##inst \ | |
| 177 }, \ | |
| 178 { \ | |
| 179 STR(inst) "_alloca", test_alloca_##inst, Subzero_::test_alloca_##inst \ | |
| 180 }, | |
| 181 RMWOP_TABLE | |
| 182 #undef X | |
| 183 }; | |
| 184 const static size_t NumFuncs = sizeof(Funcs) / sizeof(*Funcs); | |
| 185 | |
| 186 // Just test a few values, otherwise it takes a *really* long time. | |
| 187 volatile uint64_t ValuesSubset[] = { 1, 0x7e, 0x000fffffffffffffffll }; | |
| 188 const size_t NumValuesSubset = sizeof(ValuesSubset) / sizeof(*ValuesSubset); | |
| 189 | |
| 190 for (size_t f = 0; f < NumFuncs; ++f) { | |
| 191 for (size_t i = 0; i < NumValuesSubset; ++i) { | |
| 192 Type Value1 = static_cast<Type>(ValuesSubset[i]); | |
| 193 for (size_t j = 0; j < NumValuesSubset; ++j) { | |
| 194 Type Value2 = static_cast<Type>(ValuesSubset[j]); | |
| 195 bool fetch_first = true; | |
| 196 ThreadData<Type> TDataSz = { | |
| 197 Funcs[f].FuncSz, fetch_first, AtomicLoc, Value2 }; | |
| 198 ThreadData<Type> TDataLlc = { | |
| 199 Funcs[f].FuncLlc, fetch_first, AtomicLoc, Value2 }; | |
| 200 ++TotalTests; | |
| 201 const size_t num_threads = 4; | |
| 202 pthread_t t[num_threads]; | |
| 203 | |
| 204 // Try N threads w/ just Llc. | |
| 205 *AtomicLoc = Value1; | |
| 206 for (size_t m = 0; m < num_threads; ++m) { | |
| 207 pthread_create(&t[m], NULL, &threadWrapper<Type>, | |
| 208 reinterpret_cast<void *>(&TDataLlc)); | |
| 209 } | |
| 210 for (size_t m = 0; m < num_threads; ++m) { | |
| 211 pthread_join(t[m], NULL); | |
| 212 } | |
| 213 Type ResultLlc = *AtomicLoc; | |
| 214 | |
| 215 // Try N threads w/ both Sz and Llc. | |
| 216 *AtomicLoc = Value1; | |
| 217 for (size_t m = 0; m < num_threads; ++m) { | |
| 218 pthread_create(&t[m], NULL, &threadWrapper<Type>, | |
|
JF
2014/07/13 19:56:12
Check the return code.
jvoung (off chromium)
2014/07/14 16:20:30
Done.
| |
| 219 m % 2 == 0 | |
| 220 ? reinterpret_cast<void *>(&TDataLlc) | |
| 221 : reinterpret_cast<void *>(&TDataSz)); | |
| 222 } | |
| 223 for (size_t m = 0; m < num_threads; ++m) { | |
| 224 pthread_join(t[m], NULL); | |
|
JF
2014/07/13 19:56:12
Ditto.
jvoung (off chromium)
2014/07/14 16:20:30
Done.
| |
| 225 } | |
| 226 Type ResultMixed = *AtomicLoc; | |
| 227 | |
| 228 if (ResultLlc == ResultMixed) { | |
| 229 ++Passes; | |
| 230 } else { | |
| 231 ++Failures; | |
| 232 std::cout << "test_with_threads_" << Funcs[f].Name | |
| 233 << (8 * sizeof(Type)) << "(" | |
| 234 << static_cast<uint64_t>(Value1) << ", " | |
| 235 << static_cast<uint64_t>(Value2) | |
| 236 << "): llc=" << static_cast<uint64_t>(ResultLlc) | |
| 237 << " mixed=" << static_cast<uint64_t>(ResultMixed) | |
| 238 << std::endl; | |
| 239 } | |
| 240 } | |
| 241 } | |
| 242 } | |
| 243 } | |
| 244 | |
| 245 int main(int argc, char **argv) { | |
| 246 size_t TotalTests = 0; | |
| 247 size_t Passes = 0; | |
| 248 size_t Failures = 0; | |
| 249 | |
| 250 testAtomicRMW<uint8_t>(&AtomicLocs.l8, TotalTests, Passes, Failures); | |
| 251 testAtomicRMW<uint16_t>(&AtomicLocs.l16, TotalTests, Passes, Failures); | |
| 252 testAtomicRMW<uint32_t>(&AtomicLocs.l32, TotalTests, Passes, Failures); | |
| 253 testAtomicRMW<uint64_t>(&AtomicLocs.l64, TotalTests, Passes, Failures); | |
| 254 testValCompareAndSwap<uint8_t>( | |
| 255 &AtomicLocs.l8, TotalTests, Passes, Failures); | |
| 256 testValCompareAndSwap<uint16_t>( | |
| 257 &AtomicLocs.l16, TotalTests, Passes, Failures); | |
| 258 testValCompareAndSwap<uint32_t>( | |
| 259 &AtomicLocs.l32, TotalTests, Passes, Failures); | |
| 260 testValCompareAndSwap<uint64_t>( | |
| 261 &AtomicLocs.l64, TotalTests, Passes, Failures); | |
| 262 testAtomicRMWThreads<uint8_t>( | |
| 263 &AtomicLocs.l8, TotalTests, Passes, Failures); | |
| 264 testAtomicRMWThreads<uint16_t>( | |
| 265 &AtomicLocs.l16, TotalTests, Passes, Failures); | |
| 266 testAtomicRMWThreads<uint32_t>( | |
| 267 &AtomicLocs.l32, TotalTests, Passes, Failures); | |
| 268 testAtomicRMWThreads<uint64_t>( | |
| 269 &AtomicLocs.l64, TotalTests, Passes, Failures); | |
| 270 | |
| 271 std::cout << "TotalTests=" << TotalTests << " Passes=" << Passes | |
| 272 << " Failures=" << Failures << "\n"; | |
| 273 return Failures; | |
| 274 } | |
| OLD | NEW |