1 // Copyright 2021 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 <xnnpack.h> 9 #include <xnnpack/params.h> 10 11 #include <numeric> 12 #include <cassert> 13 #include <cstddef> 14 #include <cstdlib> 15 #include <vector> 16 17 #include <gtest/gtest.h> 18 19 20 class TransposeMicrokernelTester { 21 public: block_height(size_t block_height)22 inline TransposeMicrokernelTester& block_height(size_t block_height) { 23 assert(block_height != 0); 24 this->block_height_ = block_height; 25 return *this; 26 } 27 block_height()28 inline size_t block_height() const { return this->block_height_; } 29 block_width(size_t block_width)30 inline TransposeMicrokernelTester& block_width(size_t block_width) { 31 assert(block_width != 0); 32 this->block_width_ = block_width; 33 return *this; 34 } 35 block_width()36 inline size_t block_width() const { return this->block_width_; } 37 input_stride(size_t input_stride)38 inline TransposeMicrokernelTester& input_stride(size_t input_stride) { 39 this->input_stride_ = input_stride; 40 return *this; 41 } 42 input_stride()43 inline size_t input_stride() const { return this->input_stride_; } 44 output_stride(size_t output_stride)45 inline TransposeMicrokernelTester& output_stride(size_t output_stride) { 46 this->output_stride_ = output_stride; 47 return *this; 48 } 49 output_stride()50 inline size_t output_stride() const { return this->output_stride_; } 51 iterations(size_t iterations)52 inline TransposeMicrokernelTester& iterations(size_t iterations) { 53 this->iterations_ = iterations; 54 return *this; 55 } 56 iterations()57 inline size_t iterations() const { return this->iterations_; } 58 Test(xnn_x64_transpose_ukernel_function transpose)59 void Test(xnn_x64_transpose_ukernel_function transpose) const { 60 std::vector<uint64_t> input(input_stride() * output_stride() + XNN_EXTRA_BYTES / sizeof(uint64_t)); 61 std::vector<uint64_t> output(input_stride() * output_stride()); 62 for (size_t iteration = 0; iteration < iterations(); iteration++) { 63 std::iota(input.begin(), input.end(), 0); 64 std::fill(output.begin(), output.end(), 0); 65 66 // Call optimized micro-kernel. 67 transpose(input.data(), 68 output.data(), 69 input_stride() * sizeof(uint64_t), 70 output_stride() * sizeof(uint64_t), 71 block_width(), 72 block_height()); 73 74 // Verify results. 75 for (size_t c = 0; c < block_width(); c++) { 76 for (size_t r = 0; r < block_height(); r++) { 77 EXPECT_EQ(input[c + r * input_stride()], output[r + c * output_stride()]) 78 << "at row " << r << " / " << block_height() 79 << ", at column " << c << " / " << block_width(); 80 } 81 } 82 } 83 } 84 Test(xnn_x32_transpose_ukernel_function transpose)85 void Test(xnn_x32_transpose_ukernel_function transpose) const { 86 std::vector<uint32_t> input(input_stride() * output_stride() + XNN_EXTRA_BYTES / sizeof(uint32_t)); 87 std::vector<uint32_t> output(input_stride() * output_stride()); 88 for (size_t iteration = 0; iteration < iterations(); iteration++) { 89 std::iota(input.begin(), input.end(), 0); 90 std::fill(output.begin(), output.end(), 0); 91 92 // Call optimized micro-kernel. 93 transpose(input.data(), 94 output.data(), 95 input_stride() * sizeof(uint32_t), 96 output_stride() * sizeof(uint32_t), 97 block_width(), 98 block_height()); 99 100 // Verify results. 101 for (size_t c = 0; c < block_width(); c++) { 102 for (size_t r = 0; r < block_height(); r++) { 103 EXPECT_EQ(input[c + r * input_stride()], output[r + c * output_stride()]) 104 << "at row " << r << " / " << block_height() 105 << ", at column " << c << " / " << block_width(); 106 } 107 } 108 } 109 } 110 Test(xnn_x16_transpose_ukernel_function transpose)111 void Test(xnn_x16_transpose_ukernel_function transpose) const { 112 std::vector<uint16_t> input(input_stride() * output_stride() + XNN_EXTRA_BYTES / sizeof(uint16_t)); 113 std::vector<uint16_t> output(input_stride() * output_stride()); 114 for (size_t iteration = 0; iteration < iterations(); iteration++) { 115 std::iota(input.begin(), input.end(), 0); 116 std::fill(output.begin(), output.end(), 0); 117 118 // Call optimized micro-kernel. 119 transpose(input.data(), 120 output.data(), 121 input_stride() * sizeof(uint16_t), 122 output_stride() * sizeof(uint16_t), 123 block_width(), 124 block_height()); 125 126 // Verify results. 127 for (size_t c = 0; c < block_width(); c++) { 128 for (size_t r = 0; r < block_height(); r++) { 129 EXPECT_EQ(input[c + r * input_stride()], output[r + c * output_stride()]) 130 << "at row " << r << " / " << block_height() 131 << ", at column " << c << " / " << block_width(); 132 } 133 } 134 } 135 } 136 Test(xnn_x8_transpose_ukernel_function transpose)137 void Test(xnn_x8_transpose_ukernel_function transpose) const { 138 std::vector<uint8_t> input(input_stride() * output_stride() + XNN_EXTRA_BYTES); 139 std::vector<uint8_t> output(input_stride() * output_stride()); 140 for (size_t iteration = 0; iteration < iterations(); iteration++) { 141 std::iota(input.begin(), input.end(), 0); 142 std::fill(output.begin(), output.end(), 0); 143 144 // Call optimized micro-kernel. 145 transpose(input.data(), 146 output.data(), 147 input_stride() * sizeof(uint8_t), 148 output_stride() * sizeof(uint8_t), 149 block_width(), 150 block_height()); 151 152 // Verify results. 153 for (size_t c = 0; c < block_width(); c++) { 154 for (size_t r = 0; r < block_height(); r++) { 155 EXPECT_EQ((int)input[c + r * input_stride()], (int)output[r + c * output_stride()]) 156 << "at row " << r << " / " << block_height() 157 << ", at column " << c << " / " << block_width(); 158 } 159 } 160 } 161 } 162 163 private: 164 size_t input_stride_ = 1; 165 size_t output_stride_ = 1; 166 size_t block_height_ = 1; 167 size_t block_width_ = 1; 168 size_t iterations_ = 15; 169 }; 170