• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 <cmath>
13 #include <cstddef>
14 #include <cstdlib>
15 #include <random>
16 #include <vector>
17 
18 #include <xnnpack.h>
19 #include <xnnpack/aligned-allocator.h>
20 #include <xnnpack/microfnptr.h>
21 
22 
23 class FilterbankAccumulateMicrokernelTester {
24  public:
rows(size_t rows)25   inline FilterbankAccumulateMicrokernelTester& rows(size_t rows) {
26     assert(rows != 0);
27     this->rows_ = rows;
28     return *this;
29   }
30 
rows()31   inline size_t rows() const {
32     return this->rows_;
33   }
34 
iterations(size_t iterations)35   inline FilterbankAccumulateMicrokernelTester& iterations(size_t iterations) {
36     this->iterations_ = iterations;
37     return *this;
38   }
39 
iterations()40   inline size_t iterations() const {
41     return this->iterations_;
42   }
43 
Test(xnn_u32_filterbank_accumulate_ukernel_function filterbank_accumulate)44   void Test(xnn_u32_filterbank_accumulate_ukernel_function filterbank_accumulate) const {
45     std::random_device random_device;
46     auto rng = std::mt19937(random_device());
47     auto u8rng = std::bind(std::uniform_int_distribution<uint16_t>(1, 10), std::ref(rng));
48     auto u16rng = std::bind(std::uniform_int_distribution<uint16_t>(), std::ref(rng));
49     auto u32rng = std::bind(std::uniform_int_distribution<uint32_t>(), std::ref(rng));
50 
51     std::vector<uint8_t> filterbank_widths(rows() + 1);
52     std::vector<uint64_t> output(rows());
53     std::vector<uint64_t> output_ref(rows());
54 
55     for (size_t iteration = 0; iteration < iterations(); iteration++) {
56       std::generate(filterbank_widths.begin(), filterbank_widths.end(), std::ref(u8rng));
57       const size_t num_channels = std::accumulate(filterbank_widths.cbegin(), filterbank_widths.cend(), 0);
58 
59       std::vector<uint32_t> input(num_channels);
60       std::vector<uint16_t> weights(num_channels * 2);
61       std::generate(input.begin(), input.end(), std::ref(u32rng));
62       std::generate(weights.begin(), weights.end(), std::ref(u16rng));
63       std::fill(output.begin(), output.end(), UINT64_C(0xCAFEB0BADEADBEAF));
64 
65       uint64_t weight_accumulator = 0;
66       uint64_t unweight_accumulator = 0;
67       size_t i = 0;
68       for (size_t m = 0; m <= rows(); m++) {
69         const size_t weight_width = filterbank_widths[m];
70         for (size_t n = 0; n < weight_width; n++) {
71           weight_accumulator += uint64_t(input[i]) * uint64_t(weights[i * 2]);
72           unweight_accumulator += uint64_t(input[i]) * uint64_t(weights[i * 2 + 1]);
73           i += 1;
74         }
75         if (m != 0) {
76           output_ref[m - 1] = weight_accumulator;
77         }
78         weight_accumulator = unweight_accumulator;
79         unweight_accumulator = 0;
80       }
81 
82       // Call optimized micro-kernel.
83       filterbank_accumulate(rows(), input.data(), filterbank_widths.data(), weights.data(), output.data());
84 
85       // Verify results.
86       for (size_t m = 0; m < rows(); m++) {
87         ASSERT_EQ(output[m], output_ref[m])
88             << "at row " << m << " / " << rows();
89       }
90     }
91   }
92 
93  private:
94   size_t rows_{1};
95   size_t iterations_{15};
96 };
97