// Copyright 2020 Google LLC // // This source code is licensed under the BSD-style license found in the // LICENSE file in the root directory of this source tree. #pragma once #include #include #include #include #include #include #include #include #include #include class FillMicrokernelTester { public: inline FillMicrokernelTester& rows(size_t rows) { assert(rows != 0); this->rows_ = rows; return *this; } inline size_t rows() const { return this->rows_; } inline FillMicrokernelTester& channels(size_t channels) { assert(channels != 0); this->channels_ = channels; return *this; } inline size_t channels() const { return this->channels_; } inline FillMicrokernelTester& output_stride(size_t output_stride) { assert(output_stride != 0); this->output_stride_ = output_stride; return *this; } inline size_t output_stride() const { if (this->output_stride_ == 0) { return channels(); } else { return this->output_stride_; } } inline FillMicrokernelTester& iterations(size_t iterations) { this->iterations_ = iterations; return *this; } inline size_t iterations() const { return this->iterations_; } void Test(xnn_x32_fill_ukernel_function fill) const { ASSERT_GE(output_stride(), channels()); std::random_device random_device; auto rng = std::mt19937(random_device()); auto u32rng = std::bind(std::uniform_int_distribution(), rng); std::vector output((rows() - 1) * output_stride() + channels()); std::vector output_copy(output.size()); for (size_t iteration = 0; iteration < iterations(); iteration++) { std::generate(output.begin(), output.end(), std::ref(u32rng)); std::copy(output.cbegin(), output.cend(), output_copy.begin()); const uint32_t fill_value = u32rng(); // Call optimized micro-kernel. fill( rows(), channels() * sizeof(uint32_t), output.data(), output_stride() * sizeof(uint32_t), &fill_value); // Verify results. for (size_t i = 0; i < rows(); i++) { for (size_t c = 0; c < channels(); c++) { ASSERT_EQ(output[i * output_stride() + c], fill_value) << "at row " << i << " / " << rows() << ", channel " << c << " / " << channels() << ", fill value 0x" << std::hex << std::setw(8) << std::setfill('0') << fill_value << ", output value 0x" << std::hex << std::setw(8) << std::setfill('0') << output[i * output_stride() + c]; } } for (size_t i = 0; i + 1 < rows(); i++) { for (size_t c = channels(); c < output_stride(); c++) { ASSERT_EQ(output[i * output_stride() + c], output_copy[i * output_stride() + c]) << "at row " << i << " / " << rows() << ", channel " << c << " / " << channels() << ", original value 0x" << std::hex << std::setw(8) << std::setfill('0') << output_copy[i * output_stride() + c] << ", output value 0x" << std::hex << std::setw(8) << std::setfill('0') << output[i * output_stride() + c]; } } } } private: size_t rows_{1}; size_t channels_{1}; size_t output_stride_{0}; size_t iterations_{15}; };