1*4bdc9457SAndroid Build Coastguard Worker // Copyright 2019 Google LLC 2*4bdc9457SAndroid Build Coastguard Worker // 3*4bdc9457SAndroid Build Coastguard Worker // This source code is licensed under the BSD-style license found in the 4*4bdc9457SAndroid Build Coastguard Worker // LICENSE file in the root directory of this source tree. 5*4bdc9457SAndroid Build Coastguard Worker 6*4bdc9457SAndroid Build Coastguard Worker #pragma once 7*4bdc9457SAndroid Build Coastguard Worker 8*4bdc9457SAndroid Build Coastguard Worker #include <gtest/gtest.h> 9*4bdc9457SAndroid Build Coastguard Worker 10*4bdc9457SAndroid Build Coastguard Worker #include <algorithm> 11*4bdc9457SAndroid Build Coastguard Worker #include <chrono> 12*4bdc9457SAndroid Build Coastguard Worker #include <cstddef> 13*4bdc9457SAndroid Build Coastguard Worker #include <cstdlib> 14*4bdc9457SAndroid Build Coastguard Worker #include <functional> 15*4bdc9457SAndroid Build Coastguard Worker #include <random> 16*4bdc9457SAndroid Build Coastguard Worker #include <vector> 17*4bdc9457SAndroid Build Coastguard Worker 18*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack.h> 19*4bdc9457SAndroid Build Coastguard Worker #include <xnnpack/microfnptr.h> 20*4bdc9457SAndroid Build Coastguard Worker 21*4bdc9457SAndroid Build Coastguard Worker 22*4bdc9457SAndroid Build Coastguard Worker class VScaleExpMinusMaxMicrokernelTester { 23*4bdc9457SAndroid Build Coastguard Worker public: elements(size_t elements)24*4bdc9457SAndroid Build Coastguard Worker inline VScaleExpMinusMaxMicrokernelTester& elements(size_t elements) { 25*4bdc9457SAndroid Build Coastguard Worker assert(elements != 0); 26*4bdc9457SAndroid Build Coastguard Worker this->elements_ = elements; 27*4bdc9457SAndroid Build Coastguard Worker return *this; 28*4bdc9457SAndroid Build Coastguard Worker } 29*4bdc9457SAndroid Build Coastguard Worker elements()30*4bdc9457SAndroid Build Coastguard Worker inline size_t elements() const { 31*4bdc9457SAndroid Build Coastguard Worker return this->elements_; 32*4bdc9457SAndroid Build Coastguard Worker } 33*4bdc9457SAndroid Build Coastguard Worker scale(float scale)34*4bdc9457SAndroid Build Coastguard Worker inline VScaleExpMinusMaxMicrokernelTester& scale(float scale) { 35*4bdc9457SAndroid Build Coastguard Worker assert(std::isfinite(scale)); 36*4bdc9457SAndroid Build Coastguard Worker assert(scale > 0); 37*4bdc9457SAndroid Build Coastguard Worker this->scale_ = scale; 38*4bdc9457SAndroid Build Coastguard Worker return *this; 39*4bdc9457SAndroid Build Coastguard Worker } 40*4bdc9457SAndroid Build Coastguard Worker scale()41*4bdc9457SAndroid Build Coastguard Worker inline float scale() const { 42*4bdc9457SAndroid Build Coastguard Worker return this->scale_; 43*4bdc9457SAndroid Build Coastguard Worker } 44*4bdc9457SAndroid Build Coastguard Worker iterations(size_t iterations)45*4bdc9457SAndroid Build Coastguard Worker inline VScaleExpMinusMaxMicrokernelTester& iterations(size_t iterations) { 46*4bdc9457SAndroid Build Coastguard Worker this->iterations_ = iterations; 47*4bdc9457SAndroid Build Coastguard Worker return *this; 48*4bdc9457SAndroid Build Coastguard Worker } 49*4bdc9457SAndroid Build Coastguard Worker iterations()50*4bdc9457SAndroid Build Coastguard Worker inline size_t iterations() const { 51*4bdc9457SAndroid Build Coastguard Worker return this->iterations_; 52*4bdc9457SAndroid Build Coastguard Worker } 53*4bdc9457SAndroid Build Coastguard Worker Test(xnn_f32_vscaleexpminusmax_ukernel_function vscaleexpminusmax)54*4bdc9457SAndroid Build Coastguard Worker void Test(xnn_f32_vscaleexpminusmax_ukernel_function vscaleexpminusmax) const { 55*4bdc9457SAndroid Build Coastguard Worker std::random_device random_device; 56*4bdc9457SAndroid Build Coastguard Worker auto rng = std::mt19937(random_device()); 57*4bdc9457SAndroid Build Coastguard Worker // Choose such range that expf(x[i]) overflows, but expf(x[i] - x_max) doesn't. 58*4bdc9457SAndroid Build Coastguard Worker // However, the range is still narrow enough that double-precision exp doesn't overflow. 59*4bdc9457SAndroid Build Coastguard Worker auto f32rng = std::bind(std::uniform_real_distribution<float>(90.0f, 100.0f), rng); 60*4bdc9457SAndroid Build Coastguard Worker 61*4bdc9457SAndroid Build Coastguard Worker std::vector<float> x(elements() + XNN_EXTRA_BYTES / sizeof(float)); 62*4bdc9457SAndroid Build Coastguard Worker std::vector<float> y(elements()); 63*4bdc9457SAndroid Build Coastguard Worker std::vector<double> y_ref(elements()); 64*4bdc9457SAndroid Build Coastguard Worker for (size_t iteration = 0; iteration < iterations(); iteration++) { 65*4bdc9457SAndroid Build Coastguard Worker std::generate(x.begin(), x.end(), std::ref(f32rng)); 66*4bdc9457SAndroid Build Coastguard Worker 67*4bdc9457SAndroid Build Coastguard Worker // Compute reference results. 68*4bdc9457SAndroid Build Coastguard Worker const float x_max = *std::max_element(x.begin(), x.begin() + elements()); 69*4bdc9457SAndroid Build Coastguard Worker for (size_t i = 0; i < elements(); i++) { 70*4bdc9457SAndroid Build Coastguard Worker y_ref[i] = double(scale()) * exp(double(x[i]) - double(x_max)); 71*4bdc9457SAndroid Build Coastguard Worker } 72*4bdc9457SAndroid Build Coastguard Worker 73*4bdc9457SAndroid Build Coastguard Worker // Call optimized micro-kernel. 74*4bdc9457SAndroid Build Coastguard Worker vscaleexpminusmax(elements() * sizeof(float), x.data(), y.data(), scale(), x_max); 75*4bdc9457SAndroid Build Coastguard Worker 76*4bdc9457SAndroid Build Coastguard Worker // Verify results. 77*4bdc9457SAndroid Build Coastguard Worker for (size_t i = 0; i < elements(); i++) { 78*4bdc9457SAndroid Build Coastguard Worker ASSERT_NEAR(y_ref[i], y[i], std::abs(y_ref[i]) * 1.0e-6) 79*4bdc9457SAndroid Build Coastguard Worker << "elements = " << elements() << ", scale = " << scale() << ", x_max = " << x_max; 80*4bdc9457SAndroid Build Coastguard Worker } 81*4bdc9457SAndroid Build Coastguard Worker } 82*4bdc9457SAndroid Build Coastguard Worker } 83*4bdc9457SAndroid Build Coastguard Worker 84*4bdc9457SAndroid Build Coastguard Worker private: 85*4bdc9457SAndroid Build Coastguard Worker size_t elements_{1}; 86*4bdc9457SAndroid Build Coastguard Worker float scale_{1.0f}; 87*4bdc9457SAndroid Build Coastguard Worker size_t iterations_{15}; 88*4bdc9457SAndroid Build Coastguard Worker }; 89