ROOT  6.06/09
Reference Guide
utils.cpp
Go to the documentation of this file.
1 /* This file is part of the Vc library.
2 
3  Copyright (C) 2009-2012 Matthias Kretz <kretz@kde.org>
4 
5  Vc is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as
7  published by the Free Software Foundation, either version 3 of
8  the License, or (at your option) any later version.
9 
10  Vc is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public
16  License along with Vc. If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 
20 #include "unittest.h"
21 #include <iostream>
22 #include "vectormemoryhelper.h"
23 #include <Vc/cpuid.h>
24 
25 using namespace Vc;
26 
27 template<typename Vec> void testSort()
28 {
29  typedef typename Vec::IndexType IndexType;
30 
31  const IndexType _ref(IndexesFromZero);
32  Vec ref(_ref);
33  Vec a;
34  int maxPerm = 1;
35  for (int x = Vec::Size; x > 0; --x) {
36  maxPerm *= x;
37  }
38  for (int perm = 0; perm < maxPerm; ++perm) {
39  int rest = perm;
40  for (int i = 0; i < Vec::Size; ++i) {
41  a[i] = 0;
42  for (int j = 0; j < i; ++j) {
43  if (a[i] == a[j]) {
44  ++(a[i]);
45  j = -1;
46  }
47  }
48  a[i] += rest % (Vec::Size - i);
49  rest /= (Vec::Size - i);
50  for (int j = 0; j < i; ++j) {
51  if (a[i] == a[j]) {
52  ++(a[i]);
53  j = -1;
54  }
55  }
56  }
57  //std::cout << a << a.sorted() << std::endl;
58  COMPARE(ref, a.sorted()) << ", a: " << a;
59  }
60 
61  for (int repetition = 0; repetition < 1000; ++repetition) {
62  Vec test = Vec::Random();
64  reference.vector(0) = test;
65  std::sort(&reference[0], &reference[Vec::Size]);
66  ref = reference.vector(0);
67  COMPARE(ref, test.sorted());
68  }
69 }
70 
71 template<typename T, typename Mem> struct Foo
72 {
73  Foo() : i(0) {}
74  void reset() { i = 0; }
75  void operator()(T v) { d[i++] = v; }
76  Mem d;
77  int i;
78 };
79 
80 template<typename V> void testCall()
81 {
82  typedef typename V::EntryType T;
83  typedef typename V::IndexType I;
84  typedef typename V::Mask M;
85  typedef typename I::Mask MI;
86  const I _indexes(IndexesFromZero);
87  const MI _odd = (_indexes & I(One)) > 0;
88  const M odd(_odd);
89  V a(_indexes);
90  Foo<T, typename V::Memory> f;
91  a.callWithValuesSorted(f);
92  V b(f.d);
93  COMPARE(b, a);
94 
95  f.reset();
96  a(odd) -= 1;
97  a.callWithValuesSorted(f);
98  V c(f.d);
99  for (int i = 0; i < V::Size / 2; ++i) {
100  COMPARE(a[i * 2], c[i]);
101  }
102  for (int i = V::Size / 2; i < V::Size; ++i) {
103  COMPARE(b[i], c[i]);
104  }
105 }
106 
107 template<typename V> void testForeachBit()
108 {
109  typedef typename V::EntryType T;
110  typedef typename V::IndexType I;
111  const I indexes(IndexesFromZero);
112  for_all_masks(V, mask) {
113  V tmp = V::Zero();
114  foreach_bit(int j, mask) {
115  tmp[j] = T(1);
116  }
117  COMPARE(tmp == V::One(), mask);
118 
119  int count = 0;
120  foreach_bit(int j, mask) {
121  ++count;
122  if (j >= 0) {
123  continue;
124  }
125  }
126  COMPARE(count, mask.count());
127 
128  count = 0;
129  foreach_bit(int j, mask) {
130  if (j >= 0) {
131  break;
132  }
133  ++count;
134  }
135  COMPARE(count, 0);
136  }
137 }
138 
139 template<typename V> void copySign()
140 {
141  V v(One);
142  V positive(One);
143  V negative = -positive;
144  COMPARE(v, v.copySign(positive));
145  COMPARE(-v, v.copySign(negative));
146 }
147 
148 #ifdef _WIN32
149 void bzero(void *p, size_t n) { memset(p, 0, n); }
150 #else
151 #include <strings.h>
152 #endif
153 
154 template<typename V> void Random()
155 {
156  typedef typename V::EntryType T;
157  enum {
158  NBits = 3,
159  NBins = 1 << NBits, // short int
160  TotalBits = sizeof(T) * 8, // 16 32
161  RightShift = TotalBits - NBits, // 13 29
162  NHistograms = TotalBits - NBits + 1, // 14 30
163  LeftShift = (RightShift + 1) / NHistograms,// 1 1
164  Mean = 135791,
165  MinGood = Mean - Mean/10,
166  MaxGood = Mean + Mean/10
167  };
168  const V mask((1 << NBits) - 1);
169  int histogram[NHistograms][NBins];
170  bzero(&histogram[0][0], sizeof(histogram));
171  for (size_t i = 0; i < NBins * Mean / V::Size; ++i) {
172  const V rand = V::Random();
173  for (size_t hist = 0; hist < NHistograms; ++hist) {
174  const V bin = ((rand << (hist * LeftShift)) >> RightShift) & mask;
175  for (size_t k = 0; k < V::Size; ++k) {
176  ++histogram[hist][bin[k]];
177  }
178  }
179  }
180 //#define PRINT_RANDOM_HISTOGRAM
181 #ifdef PRINT_RANDOM_HISTOGRAM
182  for (size_t hist = 0; hist < NHistograms; ++hist) {
183  std::cout << "histogram[" << std::setw(2) << hist << "]: ";
184  for (size_t bin = 0; bin < NBins; ++bin) {
185  std::cout << std::setw(3) << (histogram[hist][bin] - Mean) * 1000 / Mean << "|";
186  }
187  std::cout << std::endl;
188  }
189 #endif
190  for (size_t hist = 0; hist < NHistograms; ++hist) {
191  for (size_t bin = 0; bin < NBins; ++bin) {
192  VERIFY(histogram[hist][bin] > MinGood)
193  << " bin = " << bin << " is " << histogram[0][bin];
194  VERIFY(histogram[hist][bin] < MaxGood)
195  << " bin = " << bin << " is " << histogram[0][bin];
196  }
197  }
198 }
199 
200 template<typename V, typename I> void FloatRandom()
201 {
202  typedef typename V::EntryType T;
203  enum {
204  NBins = 64,
205  NHistograms = 1,
206  Mean = 135791,
207  MinGood = Mean - Mean/10,
208  MaxGood = Mean + Mean/10
209  };
210  int histogram[NHistograms][NBins];
211  bzero(&histogram[0][0], sizeof(histogram));
212  for (size_t i = 0; i < NBins * Mean / V::Size; ++i) {
213  const V rand = V::Random();
214  const I bin = static_cast<I>(rand * T(NBins));
215  for (size_t k = 0; k < V::Size; ++k) {
216  ++histogram[0][bin[k]];
217  }
218  }
219 #ifdef PRINT_RANDOM_HISTOGRAM
220  for (size_t hist = 0; hist < NHistograms; ++hist) {
221  std::cout << "histogram[" << std::setw(2) << hist << "]: ";
222  for (size_t bin = 0; bin < NBins; ++bin) {
223  std::cout << std::setw(3) << (histogram[hist][bin] - Mean) * 1000 / Mean << "|";
224  }
225  std::cout << std::endl;
226  }
227 #endif
228  for (size_t hist = 0; hist < NHistograms; ++hist) {
229  for (size_t bin = 0; bin < NBins; ++bin) {
230  VERIFY(histogram[hist][bin] > MinGood)
231  << " bin = " << bin << " is " << histogram[0][bin];
232  VERIFY(histogram[hist][bin] < MaxGood)
233  << " bin = " << bin << " is " << histogram[0][bin];
234  }
235  }
236 }
237 
238 template<> void Random<float_v>() { FloatRandom<float_v, int_v>(); }
239 template<> void Random<double_v>() { FloatRandom<double_v, int_v>(); }
240 template<> void Random<sfloat_v>() { FloatRandom<sfloat_v, short_v>(); }
241 
242 template<typename T> T add2(T x) { return x + T(2); }
243 
244 template<typename T, typename V>
245 class CallTester
246 {
247  public:
248  CallTester() : v(Vc::Zero), i(0) {}
249 
250  void operator()(T x) {
251  v[i] = x;
252  ++i;
253  }
254 
255  void reset() { v.setZero(); i = 0; }
256 
257  int callCount() const { return i; }
258  V callValues() const { return v; }
259 
260  private:
261  V v;
262  int i;
263 };
264 
265 #if __cplusplus >= 201103 && (!defined(VC_CLANG) || VC_CLANG > 0x30000)
266 #define DO_LAMBDA_TESTS 1
267 #endif
268 
269 template<typename V>
271 {
272  typedef typename V::EntryType T;
273 
274  const V two(T(2));
275  for (int i = 0; i < 1000; ++i) {
276  const V rand = V::Random();
277  COMPARE(rand.apply(add2<T>), rand + two);
278 #ifdef DO_LAMBDA_TESTS
279  COMPARE(rand.apply([](T x) { return x + T(2); }), rand + two);
280 #endif
281 
282  CallTester<T, V> callTester;
283  rand.call(callTester);
284  COMPARE(callTester.callCount(), int(V::Size));
285  COMPARE(callTester.callValues(), rand);
286 
287  for_all_masks(V, mask) {
288  V copy1 = rand;
289  V copy2 = rand;
290  copy1(mask) += two;
291 
292  COMPARE(copy2(mask).apply(add2<T>), copy1) << mask;
293  COMPARE(rand.apply(add2<T>, mask), copy1) << mask;
294 #ifdef DO_LAMBDA_TESTS
295  COMPARE(copy2(mask).apply([](T x) { return x + T(2); }), copy1) << mask;
296  COMPARE(rand.apply([](T x) { return x + T(2); }, mask), copy1) << mask;
297 #endif
298 
299  callTester.reset();
300  copy2(mask).call(callTester);
301  COMPARE(callTester.callCount(), mask.count());
302 
303  callTester.reset();
304  rand.call(callTester, mask);
305  COMPARE(callTester.callCount(), mask.count());
306  }
307  }
308 }
309 
310 template<typename T, int value> T returnConstant() { return T(value); }
311 template<typename T, int value> T returnConstantOffset(int i) { return T(value) + T(i); }
312 template<typename T, int value> T returnConstantOffset2(unsigned short i) { return T(value) + T(i); }
313 
314 template<typename V> void fill()
315 {
316  typedef typename V::EntryType T;
317  typedef typename V::IndexType I;
318  V test = V::Random();
319  test.fill(returnConstant<T, 2>);
320  COMPARE(test, V(T(2)));
321 
322  test = V::Random();
323  test.fill(returnConstantOffset<T, 0>);
324  COMPARE(test, static_cast<V>(I::IndexesFromZero()));
325 
326  test = V::Random();
327  test.fill(returnConstantOffset2<T, 0>);
328  COMPARE(test, static_cast<V>(I::IndexesFromZero()));
329 }
330 
331 template<typename V> void shifted()
332 {
333  typedef typename V::EntryType T;
334  for (int shift = -2 * V::Size; shift <= 2 * V::Size; ++shift) {
335  const V reference = V::Random();
336  const V test = reference.shifted(shift);
337  for (int i = 0; i < V::Size; ++i) {
338  if (i + shift >= 0 && i + shift < V::Size) {
339  COMPARE(test[i], reference[i + shift]) << "shift: " << shift << ", i: " << i << ", test: " << test << ", reference: " << reference;
340  } else {
341  COMPARE(test[i], T(0)) << "shift: " << shift << ", i: " << i << ", test: " << test << ", reference: " << reference;
342  }
343  }
344  }
345 }
346 
347 template<typename V> void rotated()
348 {
349  for (int shift = -2 * V::Size; shift <= 2 * V::Size; ++shift) {
350  //std::cout << "amount = " << shift % V::Size << std::endl;
351  const V reference = V::Random();
352  const V test = reference.rotated(shift);
353  for (int i = 0; i < V::Size; ++i) {
354  unsigned int refShift = i + shift;
355  COMPARE(test[i], reference[refShift % V::Size]) << "shift: " << shift << ", i: " << i << ", test: " << test << ", reference: " << reference;
356  }
357  }
358 }
359 
361 {
362  int_v *a = Vc::malloc<int_v, Vc::AlignOnVector>(10);
363 
364  unsigned long mask = VectorAlignment - 1;
365  for (int i = 0; i < 10; ++i) {
366  VERIFY((reinterpret_cast<unsigned long>(&a[i]) & mask) == 0);
367  }
368  const char *data = reinterpret_cast<const char *>(&a[0]);
369  for (int i = 0; i < 10; ++i) {
370  VERIFY(&data[i * int_v::Size * sizeof(int_v::EntryType)] == reinterpret_cast<const char *>(&a[i]));
371  }
372 
373  a = Vc::malloc<int_v, Vc::AlignOnCacheline>(10);
374  mask = CpuId::cacheLineSize() - 1;
375  COMPARE((reinterpret_cast<unsigned long>(&a[0]) & mask), 0ul);
376 
377  // I don't know how to properly check page alignment. So we check for 4 KiB alignment as this is
378  // the minimum page size on x86
379  a = Vc::malloc<int_v, Vc::AlignOnPage>(10);
380  mask = 4096 - 1;
381  COMPARE((reinterpret_cast<unsigned long>(&a[0]) & mask), 0ul);
382 }
383 
384 int main()
385 {
390 
394 
397 
399 
400  return 0;
401 }
void FloatRandom()
Definition: utils.cpp:200
T add2(T x)
Definition: utils.cpp:242
Float_t Mem()
Definition: kDTreeTest.cxx:35
const char * Size
Definition: TXMLSetup.cxx:56
double T(double x)
Definition: ChebyshevPol.h:34
void shifted()
Definition: utils.cpp:331
TArc * a
Definition: textangle.C:12
void Random< sfloat_v >()
Definition: utils.cpp:240
T returnConstantOffset(int i)
Definition: utils.cpp:311
Double_t x[n]
Definition: legend1.C:17
#define COMPARE(a, b)
Definition: unittest.h:509
#define foreach_bit(_it_, _mask_)
Definition: vector.h:146
#define testRealTypes(name)
Definition: unittest.h:51
#define testAllTypes(name)
Definition: unittest.h:43
int main()
Definition: utils.cpp:384
Vc_ALWAYS_INLINE Vc_PURE VectorPointerHelper< V, AlignedFlag > vector(size_t i)
Definition: memorybase.h:310
#define for_all_masks(VecType, _mask_)
Definition: unittest.h:677
VECTOR_NAMESPACE::int_v int_v
Definition: vector.h:86
void Random< float_v >()
Definition: utils.cpp:238
SVector< double, 2 > v
Definition: Dict.h:5
void applyAndCall()
Definition: utils.cpp:270
void testCall()
Definition: utils.cpp:80
Double_t Mean(Long64_t n, const T *a, const Double_t *w=0)
Definition: TMath.h:824
void rotated()
Definition: utils.cpp:347
#define VERIFY(cond)
Definition: unittest.h:515
A helper class for fixed-size two-dimensional arrays.
Definition: memory.h:120
TRObject operator()(const T1 &t1) const
double f(double x)
void Random()
Definition: utils.cpp:154
void fill()
Definition: utils.cpp:314
void Random< double_v >()
Definition: utils.cpp:239
void copySign()
Definition: utils.cpp:139
static ushort cacheLineSize()
Return the cache line size in bits.
Definition: cpuid.h:65
void testSort()
Definition: utils.cpp:27
void testForeachBit()
Definition: utils.cpp:107
T returnConstant()
Definition: utils.cpp:310
Definition: casts.h:28
T returnConstantOffset2(unsigned short i)
Definition: utils.cpp:312
#define I(x, y, z)
float value
Definition: math.cpp:443
const Int_t n
Definition: legend1.C:16
void testMallocAlignment()
Definition: utils.cpp:360
#define runTest(name)
Definition: unittest.h:42