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/AlignedAllocator.h> 20 #include <xnnpack/params.h> 21 22 23 class PackMicrokernelTester { 24 public: mr(size_t mr)25 inline PackMicrokernelTester& mr(size_t mr) { 26 assert(mr != 0); 27 this->mr_ = mr; 28 return *this; 29 } 30 mr()31 inline size_t mr() const { 32 return this->mr_; 33 } 34 m(size_t m)35 inline PackMicrokernelTester& m(size_t m) { 36 assert(m != 0); 37 this->m_ = m; 38 return *this; 39 } 40 m()41 inline size_t m() const { 42 return this->m_; 43 } 44 k(size_t k)45 inline PackMicrokernelTester& k(size_t k) { 46 assert(k != 0); 47 this->k_ = k; 48 return *this; 49 } 50 k()51 inline size_t k() const { 52 return this->k_; 53 } 54 x_stride(size_t x_stride)55 inline PackMicrokernelTester& x_stride(size_t x_stride) { 56 assert(x_stride != 0); 57 this->x_stride_ = x_stride; 58 return *this; 59 } 60 x_stride()61 inline size_t x_stride() const { 62 if (this->x_stride_ == 0) { 63 return k(); 64 } else { 65 assert(this->x_stride_ >= k()); 66 return this->x_stride_; 67 } 68 } 69 iterations(size_t iterations)70 inline PackMicrokernelTester& iterations(size_t iterations) { 71 this->iterations_ = iterations; 72 return *this; 73 } 74 iterations()75 inline size_t iterations() const { 76 return this->iterations_; 77 } 78 Test(xnn_x32_packx_ukernel_function packx)79 void Test(xnn_x32_packx_ukernel_function packx) const { 80 std::random_device random_device; 81 auto rng = std::mt19937(random_device()); 82 auto u32rng = std::bind(std::uniform_int_distribution<uint32_t>(), rng); 83 84 const uint32_t c = u32rng(); 85 std::vector<uint32_t> x(k() + (m() - 1) * x_stride() + XNN_EXTRA_BYTES / sizeof(uint32_t)); 86 std::vector<uint32_t, AlignedAllocator<uint32_t, 64>> y(mr() * k()); 87 std::vector<uint32_t> y_ref(mr() * k()); 88 for (size_t iteration = 0; iteration < iterations(); iteration++) { 89 std::generate(x.begin(), x.end(), std::ref(u32rng)); 90 std::generate(y.begin(), y.end(), std::ref(u32rng)); 91 92 // Compute reference results. 93 std::fill(y_ref.begin(), y_ref.end(), c); 94 for (size_t i = 0; i < mr(); i++) { 95 for (size_t j = 0; j < k(); j++) { 96 y_ref[j * mr() + i] = x[std::min(i, m() - 1) * x_stride() + j]; 97 } 98 } 99 100 // Call optimized micro-kernel. 101 packx( 102 m(), k(), 103 x.data(), x_stride() * sizeof(uint32_t), 104 y.data()); 105 106 // Verify results. 107 for (size_t i = 0; i < mr(); i++) { 108 for (size_t j = 0; j < k(); j++) { 109 ASSERT_EQ(y_ref[j * mr() + i], y[j * mr() + i]) 110 << "at pixel = " << i << ", channel = " << j << ", " 111 << "m = " << m() << ", k = " << k(); 112 } 113 } 114 } 115 } 116 117 private: 118 size_t mr_{1}; 119 size_t m_{1}; 120 size_t k_{1}; 121 size_t x_stride_{0}; 122 size_t iterations_{1}; 123 }; 124