Grok 12.0.1
test_util.h
Go to the documentation of this file.
1// Copyright 2021 Google LLC
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#ifndef HWY_TESTS_TEST_UTIL_H_
17#define HWY_TESTS_TEST_UTIL_H_
18
19// Target-independent helper functions for use by *_test.cc.
20
21#include <string.h>
22
23#include <cmath> // std::isnan
24#include <string>
25
26#include "hwy/base.h"
27#include "hwy/print.h"
28
29namespace hwy {
30
31// The maximum vector size used in tests when defining test data. DEPRECATED.
33
34// 64-bit random generator (Xorshift128+). Much smaller state than std::mt19937,
35// which triggers a compiler bug.
37 public:
38 explicit RandomState(const uint64_t seed = 0x123456789ull) {
39 s0_ = SplitMix64(seed + 0x9E3779B97F4A7C15ull);
41 }
42
44 uint64_t s1 = s0_;
45 const uint64_t s0 = s1_;
46 const uint64_t bits = s1 + s0;
47 s0_ = s0;
48 s1 ^= s1 << 23;
49 s1 ^= s0 ^ (s1 >> 18) ^ (s0 >> 5);
50 s1_ = s1;
51 return bits;
52 }
53
54 private:
55 static uint64_t SplitMix64(uint64_t z) {
56 z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9ull;
57 z = (z ^ (z >> 27)) * 0x94D049BB133111EBull;
58 return z ^ (z >> 31);
59 }
60
61 uint64_t s0_;
62 uint64_t s1_;
63};
64
65static HWY_INLINE uint32_t Random32(RandomState* rng) {
66 return static_cast<uint32_t>((*rng)());
67}
68
69static HWY_INLINE uint64_t Random64(RandomState* rng) { return (*rng)(); }
70
71template <class T, HWY_IF_FLOAT_OR_SPECIAL(T)>
73 const uint64_t rand_bits = Random64(rng);
74
75 using TU = MakeUnsigned<T>;
76 constexpr TU kExponentMask = ExponentMask<T>();
77 constexpr TU kSignMantMask = static_cast<TU>(~kExponentMask);
78 constexpr TU kMaxExpField = static_cast<TU>(MaxExponentField<T>());
79 constexpr int kNumOfMantBits = MantissaBits<T>();
80
81 const TU orig_exp_field_val =
82 static_cast<TU>((rand_bits >> kNumOfMantBits) & kMaxExpField);
83
84 const TU sign_mant_bits = static_cast<TU>(rand_bits & kSignMantMask);
85 const TU exp_bits =
86 static_cast<TU>(HWY_MIN(HWY_MAX(orig_exp_field_val, 1), kMaxExpField - 1)
87 << kNumOfMantBits);
88
89 return BitCastScalar<T>(static_cast<TU>(sign_mant_bits | exp_bits));
90}
91
92template <class T, HWY_IF_NOT_FLOAT_NOR_SPECIAL(T)>
93static HWY_INLINE T RandomFiniteValue(RandomState* rng) {
94 using TU = MakeUnsigned<T>;
95 return static_cast<T>(Random64(rng) & LimitsMax<TU>());
96}
97
98HWY_TEST_DLLEXPORT bool BytesEqual(const void* p1, const void* p2, size_t size,
99 size_t* pos = nullptr);
100
101void AssertStringEqual(const char* expected, const char* actual,
102 const char* target_name, const char* filename, int line);
103
104namespace detail {
105
106template <typename T, typename TU = MakeUnsigned<T>>
107TU ComputeUlpDelta(const T expected, const T actual) {
108 // Handle -0 == 0 and infinities.
109 if (expected == actual) return 0;
110
111 // Consider "equal" if both are NaN, so we can verify an expected NaN.
112 // Needs a special case because there are many possible NaN representations.
113 if (std::isnan(expected) && std::isnan(actual)) return 0;
114
115 // Compute the difference in units of last place. We do not need to check for
116 // differing signs; they will result in large differences, which is fine.
117 TU ux, uy;
118 CopySameSize(&expected, &ux);
119 CopySameSize(&actual, &uy);
120
121 // Avoid unsigned->signed cast: 2's complement is only guaranteed by C++20.
122 const TU ulp = HWY_MAX(ux, uy) - HWY_MIN(ux, uy);
123 return ulp;
124}
125
126HWY_TEST_DLLEXPORT bool IsEqual(const TypeInfo& info, const void* expected_ptr,
127 const void* actual_ptr);
128
130 const TypeInfo& info, const void* expected_ptr, const void* actual_ptr,
131 const char* target_name, const char* filename, int line, size_t lane = 0,
132 size_t num_lanes = 1);
133
135 const void* expected_void,
136 const void* actual_void, size_t N,
137 const char* target_name,
138 const char* filename, int line);
139
140} // namespace detail
141
142// Returns a name for the vector/part/scalar. The type prefix is u/i/f for
143// unsigned/signed/floating point, followed by the number of bits per lane;
144// then 'x' followed by the number of lanes. Example: u8x16. This is useful for
145// understanding which instantiation of a generic test failed.
146template <typename T>
147std::string TypeName(T /*unused*/, size_t N) {
148 char string100[100];
149 detail::TypeName(detail::MakeTypeInfo<T>(), N, string100);
150 return string100;
151}
152
153// Type large enough to hold either value, to which we cast for comparison.
154template <typename T1, typename T2>
155using LargestType = If<IsFloat<T1>() || IsFloat<T2>(),
156 FloatFromSize<HWY_MAX(sizeof(T1), sizeof(T2))>,
157 If<IsSigned<T1>() || IsSigned<T2>(),
158 SignedFromSize<HWY_MAX(sizeof(T1), sizeof(T2))>,
159 UnsignedFromSize<HWY_MAX(sizeof(T1), sizeof(T2))>>>;
160
161// TTo is the lane type of the actual value and T is an often but not
162// necessarily larger type of the expected value. Especially for 8-bit lanes
163// initialized via Iota, the actual value often wraps around. To ensure it still
164// compares equal to the expected value, wrap integers.
165// 1) < 64-bit integer: mask
166template <typename TTo, typename T, HWY_IF_NOT_FLOAT_NOR_SPECIAL(TTo),
167 HWY_IF_T_SIZE_LE(TTo, 4)>
168T WrapTo(T value) {
169 return static_cast<T>(static_cast<uint64_t>(value) &
170 ((uint64_t{1} << (sizeof(TTo) * 8)) - 1));
171}
172// 2) 64-bit integer: no mask (shift would overflow)
173template <typename TTo, typename T, HWY_IF_NOT_FLOAT_NOR_SPECIAL(TTo),
174 HWY_IF_T_SIZE_GT(TTo, 4)>
175T WrapTo(T value) {
176 return value;
177}
178// 3) float or special: do nothing because their value range is sufficient for
179// Iota for any vector length.
180template <typename TTo, typename T, HWY_IF_FLOAT_OR_SPECIAL(TTo)>
181T WrapTo(T value) {
182 return value;
183}
184
185// Compare non-vector, non-string T, after promoting to the largest type.
186template <typename TExpected, typename TActual>
187HWY_INLINE bool IsEqual(const TExpected texpected, const TActual actual) {
188 const TActual expected = ConvertScalarTo<TActual>(WrapTo<TActual>(texpected));
189 const auto info = detail::MakeTypeInfo<TActual>();
190 return detail::IsEqual(info, &expected, &actual);
191}
192
193template <typename TExpected, typename TActual>
194HWY_INLINE void AssertEqual(const TExpected texpected, const TActual actual,
195 const char* target_name, const char* filename,
196 int line, size_t lane = 0) {
197 const TActual expected = ConvertScalarTo<TActual>(WrapTo<TActual>(texpected));
198 const auto info = detail::MakeTypeInfo<TActual>();
199 if (!detail::IsEqual(info, &expected, &actual)) {
200 detail::PrintMismatchAndAbort(info, &expected, &actual, target_name,
201 filename, line, lane);
202 }
203}
204
205template <typename T>
206HWY_INLINE void AssertArrayEqual(const T* expected, const T* actual,
207 size_t count, const char* target_name,
208 const char* filename, int line) {
209 const auto info = hwy::detail::MakeTypeInfo<T>();
210 detail::AssertArrayEqual(info, expected, actual, count, target_name, filename,
211 line);
212}
213
214// Compare with tolerance due to FMA and f16 precision.
215template <typename T>
216HWY_INLINE void AssertArraySimilar(const T* expected, const T* actual,
217 size_t count, const char* target_name,
218 const char* filename, int line) {
219 const double tolerance =
220 (hwy::IsSame<RemoveCvRef<T>, float16_t>() ? 128.0 : 1.0) /
221 (uint64_t{1} << MantissaBits<T>());
222 for (size_t i = 0; i < count; ++i) {
223 const double exp = ConvertScalarTo<double>(expected[i]);
224 const double act = ConvertScalarTo<double>(actual[i]);
225 const double l1 = ScalarAbs(act - exp);
226 // Cannot divide, so check absolute error.
227 if (exp == 0.0) {
228 if (l1 > tolerance) {
229 HWY_ABORT("%s %s:%d %s mismatch %zu of %zu: %E %E l1 %E tol %E\n",
230 target_name, filename, line, TypeName(T(), 1).c_str(), i,
231 count, exp, act, l1, tolerance);
232 }
233 } else { // relative
234 const double rel = l1 / exp;
235 if (rel > tolerance) {
236 HWY_ABORT("%s %s:%d %s mismatch %zu of %zu: %E %E rel %E tol %E\n",
237 target_name, filename, line, TypeName(T(), 1).c_str(), i,
238 count, exp, act, rel, tolerance);
239 }
240 }
241 }
242}
243
244} // namespace hwy
245
246#endif // HWY_TESTS_TEST_UTIL_H_
#define HWY_MAX(a, b)
Definition base.h:177
#define HWY_IF_T_SIZE_LE(T, bytes)
Definition base.h:647
#define HWY_NORETURN
Definition base.h:105
#define HWY_MIN(a, b)
Definition base.h:176
#define HWY_ABORT(format,...)
Definition base.h:233
#define HWY_INLINE
Definition base.h:101
#define HWY_IF_T_SIZE_GT(T, bytes)
Definition base.h:649
#define HWY_MAYBE_UNUSED
Definition base.h:113
#define HWY_IF_NOT_FLOAT_NOR_SPECIAL(T)
Definition base.h:635
Definition test_util.h:36
static uint64_t SplitMix64(uint64_t z)
Definition test_util.h:55
HWY_INLINE uint64_t operator()()
Definition test_util.h:43
uint64_t s0_
Definition test_util.h:61
uint64_t s1_
Definition test_util.h:62
RandomState(const uint64_t seed=0x123456789ull)
Definition test_util.h:38
#define HWY_TEST_DLLEXPORT
Definition highway_export.h:15
HWY_DLLEXPORT void TypeName(const TypeInfo &info, size_t N, char *string100)
TU ComputeUlpDelta(const T expected, const T actual)
Definition test_util.h:107
HWY_TEST_DLLEXPORT HWY_NORETURN void PrintMismatchAndAbort(const TypeInfo &info, const void *expected_ptr, const void *actual_ptr, const char *target_name, const char *filename, int line, size_t lane=0, size_t num_lanes=1)
HWY_TEST_DLLEXPORT bool IsEqual(const TypeInfo &info, const void *expected_ptr, const void *actual_ptr)
HWY_TEST_DLLEXPORT void AssertArrayEqual(const TypeInfo &info, const void *expected_void, const void *actual_void, size_t N, const char *target_name, const char *filename, int line)
Definition abort.h:8
void AssertStringEqual(const char *expected, const char *actual, const char *target_name, const char *filename, int line)
HWY_INLINE void AssertEqual(const TExpected texpected, const TActual actual, const char *target_name, const char *filename, int line, size_t lane=0)
Definition test_util.h:194
typename detail::Relations< T >::Unsigned MakeUnsigned
Definition base.h:2078
HWY_API void CopySameSize(const From *HWY_RESTRICT from, To *HWY_RESTRICT to)
Definition base.h:346
HWY_INLINE void AssertArrayEqual(const T *expected, const T *actual, size_t count, const char *target_name, const char *filename, int line)
Definition test_util.h:206
typename IfT< Condition, Then, Else >::type If
Definition base.h:520
typename detail::TypeFromSize< N >::Unsigned UnsignedFromSize
Definition base.h:2092
static HWY_INLINE T RandomFiniteValue(RandomState *rng)
Definition test_util.h:72
typename detail::TypeFromSize< N >::Signed SignedFromSize
Definition base.h:2094
static HWY_INLINE uint64_t Random64(RandomState *rng)
Definition test_util.h:69
std::string TypeName(T, size_t N)
Definition test_util.h:147
typename detail::TypeFromSize< N >::Float FloatFromSize
Definition base.h:2096
If< IsFloat< T1 >()||IsFloat< T2 >(), FloatFromSize< HWY_MAX(sizeof(T1), sizeof(T2))>, If< IsSigned< T1 >()||IsSigned< T2 >(), SignedFromSize< HWY_MAX(sizeof(T1), sizeof(T2))>, UnsignedFromSize< HWY_MAX(sizeof(T1), sizeof(T2))> > > LargestType
Definition test_util.h:155
static HWY_INLINE uint32_t Random32(RandomState *rng)
Definition test_util.h:65
HWY_INLINE bool IsEqual(const TExpected texpected, const TActual actual)
Definition test_util.h:187
HWY_API HWY_BITCASTSCALAR_CONSTEXPR RemoveCvRef< T > ScalarAbs(T val)
Definition base.h:2815
HWY_INLINE void AssertArraySimilar(const T *expected, const T *actual, size_t count, const char *target_name, const char *filename, int line)
Definition test_util.h:216
HWY_TEST_DLLEXPORT bool BytesEqual(const void *p1, const void *p2, size_t size, size_t *pos=nullptr)
T WrapTo(T value)
Definition test_util.h:168
HWY_MAYBE_UNUSED constexpr size_t kTestMaxVectorSize
Definition test_util.h:32
HWY_DLLEXPORT HWY_NORETURN void int line
Definition base.h:231
Definition print.h:33
Definition base.h:1117