1 // Copyright 2019 Google LLC 2 // 3 // This source code is licensed under the BSD-style license found in the 4 // LICENSE file in the root directory of this source tree. 5 6 #pragma once 7 8 #include <gtest/gtest.h> 9 10 #include <algorithm> 11 #include <cassert> 12 #include <cstddef> 13 #include <cstdlib> 14 #include <functional> 15 #include <random> 16 #include <vector> 17 18 #include <xnnpack.h> 19 #include <xnnpack/params-init.h> 20 #include <xnnpack/params.h> 21 22 23 class UnpoolMicrokernelTester { 24 public: p(size_t p)25 inline UnpoolMicrokernelTester& p(size_t p) { 26 assert(p != 0); 27 this->p_ = p; 28 return *this; 29 } 30 p()31 inline size_t p() const { 32 return this->p_; 33 } 34 c(size_t c)35 inline UnpoolMicrokernelTester& c(size_t c) { 36 assert(c != 0); 37 this->c_ = c; 38 return *this; 39 } 40 c()41 inline size_t c() const { 42 return this->c_; 43 } 44 f(uint32_t f)45 inline UnpoolMicrokernelTester& f(uint32_t f) { 46 this->f_ = f; 47 return *this; 48 } 49 f()50 inline uint32_t f() const { 51 return this->f_; 52 } 53 y_stride(size_t y_stride)54 inline UnpoolMicrokernelTester& y_stride(size_t y_stride) { 55 assert(y_stride != 0); 56 this->y_stride_ = y_stride; 57 return *this; 58 } 59 y_stride()60 inline size_t y_stride() const { 61 if (this->y_stride_ == 0) { 62 return c(); 63 } else { 64 assert(this->y_stride_ >= c()); 65 return this->y_stride_; 66 } 67 } 68 iterations(size_t iterations)69 inline UnpoolMicrokernelTester& iterations(size_t iterations) { 70 this->iterations_ = iterations; 71 return *this; 72 } 73 iterations()74 inline size_t iterations() const { 75 return this->iterations_; 76 } 77 Test(xnn_x32_unpool_ukernel_function unpool)78 void Test(xnn_x32_unpool_ukernel_function unpool) const { 79 std::random_device random_device; 80 auto rng = std::mt19937(random_device()); 81 auto x_rng = std::bind(std::uniform_int_distribution<uint32_t>(), std::ref(rng)); 82 auto i_rng = std::bind(std::uniform_int_distribution<uint32_t>(0, uint32_t(p() - 1)), std::ref(rng)); 83 84 std::vector<uint32_t> x(c()); 85 std::vector<uint32_t> i(c()); 86 std::vector<uint32_t> y((p() - 1) * y_stride() + c()); 87 std::vector<uint32_t*> indirect_y(p()); 88 std::vector<uint32_t> y_ref((p() - 1) * y_stride() + c()); 89 for (size_t iteration = 0; iteration < iterations(); iteration++) { 90 std::generate(x.begin(), x.end(), std::ref(x_rng)); 91 std::generate(i.begin(), i.end(), std::ref(i_rng)); 92 std::generate(y.begin(), y.end(), std::ref(x_rng)); 93 94 for (size_t i = 0; i < indirect_y.size(); i++) { 95 indirect_y[i] = y.data() + i * y_stride(); 96 } 97 std::shuffle(indirect_y.begin(), indirect_y.end(), rng); 98 99 // Compute reference output. 100 std::fill(y_ref.begin(), y_ref.end(), f()); 101 for (size_t k = 0; k < c(); k++) { 102 const uint32_t idx = i[k]; 103 (indirect_y[idx] - y.data() + y_ref.data())[k] = x[k]; 104 } 105 106 // Call optimized micro-kernel. 107 unpool(p(), c(), f(), x.data(), i.data(), indirect_y.data()); 108 109 // Verify results. 110 for (size_t i = 0; i < p(); i++) { 111 for (size_t k = 0; k < c(); k++) { 112 ASSERT_EQ(y_ref[i * y_stride() + k], y[i * y_stride() + k]) 113 << "at pixel " << i << ", channel " << k 114 << ", p = " << p() << ", c = " << c(); 115 } 116 } 117 } 118 } 119 120 private: 121 size_t p_{1}; 122 size_t c_{1}; 123 uint32_t f_{0}; 124 size_t y_stride_{0}; 125 size_t iterations_{15}; 126 }; 127