• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) Facebook, Inc. and its affiliates.
2 // All rights reserved.
3 //
4 // Copyright 2019 Google LLC
5 //
6 // This source code is licensed under the BSD-style license found in the
7 // LICENSE file in the root directory of this source tree.
8 
9 #pragma once
10 
11 #include <gtest/gtest.h>
12 
13 #include <algorithm>
14 #include <cassert>
15 #include <cstddef>
16 #include <cstdlib>
17 #include <functional>
18 #include <random>
19 #include <vector>
20 
21 #include <xnnpack/params.h>
22 
23 
24 class LUTNormMicrokernelTester {
25  public:
n(size_t n)26   inline LUTNormMicrokernelTester& n(size_t n) {
27     assert(n != 0);
28     this->n_ = n;
29     return *this;
30   }
31 
n()32   inline size_t n() const {
33     return this->n_;
34   }
35 
inplace(bool inplace)36   inline LUTNormMicrokernelTester& inplace(bool inplace) {
37     this->inplace_ = inplace;
38     return *this;
39   }
40 
inplace()41   inline bool inplace() const {
42     return this->inplace_;
43   }
44 
iterations(size_t iterations)45   inline LUTNormMicrokernelTester& iterations(size_t iterations) {
46     this->iterations_ = iterations;
47     return *this;
48   }
49 
iterations()50   inline size_t iterations() const {
51     return this->iterations_;
52   }
53 
Test(xnn_u8_lut32norm_ukernel_function lutnorm)54   void Test(xnn_u8_lut32norm_ukernel_function lutnorm) const {
55     std::random_device random_device;
56     auto rng = std::mt19937(random_device());
57     auto u8rng = std::bind(std::uniform_int_distribution<uint8_t>(), rng);
58     auto u32rng = std::bind(
59       std::uniform_int_distribution<uint32_t>(1, std::numeric_limits<uint32_t>::max() / (257 * n())),
60       rng);
61 
62     std::vector<uint8_t> x(n());
63     std::vector<uint32_t> t(256);
64     std::vector<uint8_t> y(n());
65     std::vector<float> y_ref(n());
66     for (size_t iteration = 0; iteration < iterations(); iteration++) {
67       std::generate(x.begin(), x.end(), std::ref(u8rng));
68       std::generate(t.begin(), t.end(), std::ref(u32rng));
69       if (inplace()) {
70         std::generate(y.begin(), y.end(), std::ref(u8rng));
71       } else {
72         std::fill(y.begin(), y.end(), 0xA5);
73       }
74       const uint8_t* x_data = inplace() ? y.data() : x.data();
75 
76       // Compute reference results.
77       uint32_t sum = 0;
78       for (size_t i = 0; i < n(); i++) {
79         sum += t[x_data[i]];
80       }
81       for (size_t i = 0; i < n(); i++) {
82         y_ref[i] = 256.0f * float(t[x_data[i]]) / float(sum);
83         y_ref[i] = std::min(y_ref[i], 255.0f);
84       }
85 
86       // Call optimized micro-kernel.
87       lutnorm(n(), x_data, t.data(), y.data());
88 
89       // Verify results.
90       for (size_t i = 0; i < n(); i++) {
91         ASSERT_NEAR(y_ref[i], float(y[i]), 0.5f)
92           << "at position " << i << ", n = " << n() << ", sum = " << sum;
93       }
94     }
95   }
96 
97  private:
98   size_t n_{1};
99   bool inplace_{false};
100   size_t iterations_{15};
101 };
102