• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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