Home | History | Annotate | Download | only in fibonacci_extension
      1 /*
      2  * Copyright (C) 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "HalInterfaces.h"
     18 #include "Manager.h"
     19 #include "NeuralNetworks.h"
     20 #include "NeuralNetworksExtensions.h"
     21 #include "NeuralNetworksWrapperExtensions.h"
     22 #include "TestNeuralNetworksWrapper.h"
     23 #include "TypeManager.h"
     24 #include "Utils.h"
     25 #include "ValidateHal.h"
     26 
     27 #include <gtest/gtest.h>
     28 
     29 #include "FibonacciDriver.h"
     30 #include "FibonacciExtension.h"
     31 
     32 namespace android {
     33 namespace nn {
     34 namespace {
     35 
     36 using ::android::nn::test_wrapper::ExtensionModel;
     37 using ::android::nn::test_wrapper::ExtensionOperandParams;
     38 using ::android::nn::test_wrapper::ExtensionOperandType;
     39 using ::android::nn::test_wrapper::Type;
     40 
     41 class FibonacciExtensionTest : public ::testing::Test {
     42    protected:
     43     virtual void SetUp() {
     44         if (DeviceManager::get()->getUseCpuOnly()) {
     45             // This test requires the use a custom driver.
     46             GTEST_SKIP();
     47         }
     48 
     49         // Real world extension tests should run against actual hardware
     50         // implementations, but there is no hardware supporting the test
     51         // extension. Hence the sample software driver.
     52         DeviceManager::get()->forTest_registerDevice(sample_driver::FibonacciDriver::kDriverName,
     53                                                      new sample_driver::FibonacciDriver());
     54         // Discover extensions provided by registered devices.
     55         TypeManager::get()->forTest_reset();
     56 
     57         uint32_t numDevices = 0;
     58         ASSERT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
     59         ANeuralNetworksDevice* fibonacciDevice = nullptr;
     60         ANeuralNetworksDevice* cpuDevice = nullptr;
     61         for (uint32_t i = 0; i < numDevices; i++) {
     62             ANeuralNetworksDevice* device = nullptr;
     63             EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
     64             bool supportsFibonacciExtension;
     65             ASSERT_EQ(ANeuralNetworksDevice_getExtensionSupport(
     66                               device, TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
     67                               &supportsFibonacciExtension),
     68                       ANEURALNETWORKS_NO_ERROR);
     69             if (supportsFibonacciExtension) {
     70                 ASSERT_EQ(fibonacciDevice, nullptr) << "Found multiple Fibonacci drivers";
     71                 fibonacciDevice = device;
     72             } else if (DeviceManager::get()->forTest_isCpuDevice(device)) {
     73                 ASSERT_EQ(cpuDevice, nullptr) << "Found multiple CPU drivers";
     74                 cpuDevice = device;
     75             }
     76         }
     77         ASSERT_NE(fibonacciDevice, nullptr) << "Expecting Fibonacci driver to be available";
     78         ASSERT_NE(cpuDevice, nullptr) << "Expecting CPU driver to be available";
     79         mDevices = {fibonacciDevice, cpuDevice};
     80     }
     81 
     82     virtual void TearDown() {
     83         if (mExecution) {
     84             ANeuralNetworksExecution_free(mExecution);
     85         }
     86         if (mCompilation) {
     87             ANeuralNetworksCompilation_free(mCompilation);
     88         }
     89         DeviceManager::get()->forTest_reInitializeDeviceList();
     90         TypeManager::get()->forTest_reset();
     91     }
     92 
     93     void checkSupportedOperations(const std::vector<bool>& expected) {
     94         const uint32_t kMaxNumberOperations = 256;
     95         EXPECT_LE(expected.size(), kMaxNumberOperations);
     96         bool supported[kMaxNumberOperations] = {false};
     97         EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(
     98                           mModel.getHandle(), mDevices.data(), mDevices.size(), supported),
     99                   ANEURALNETWORKS_NO_ERROR);
    100         for (size_t i = 0; i < expected.size(); ++i) {
    101             SCOPED_TRACE(::testing::Message() << "i = " << i);
    102             EXPECT_EQ(supported[i], expected[i]);
    103         }
    104     }
    105 
    106     void prepareForExecution() {
    107         ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel.getHandle(), mDevices.data(),
    108                                                               mDevices.size(), &mCompilation),
    109                   ANEURALNETWORKS_NO_ERROR);
    110         ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
    111         ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &mExecution),
    112                   ANEURALNETWORKS_NO_ERROR);
    113     }
    114 
    115     std::vector<ANeuralNetworksDevice*> mDevices;
    116     ANeuralNetworksExecution* mExecution = nullptr;
    117     ANeuralNetworksCompilation* mCompilation = nullptr;
    118     ExtensionModel mModel;
    119 };
    120 
    121 void addNopOperation(ExtensionModel* model, ExtensionOperandType inputType, uint32_t input,
    122                      uint32_t output) {
    123     // Our NOP operation is ADD, which has no extension type support.
    124     ASSERT_EQ(inputType.operandType.type, ANEURALNETWORKS_TENSOR_FLOAT32);
    125     ASSERT_EQ(inputType.dimensions.size(), 1u);
    126 
    127     uint32_t inputZeros = model->addOperand(&inputType);
    128     uint32_t inputSize = inputType.dimensions[0];
    129     uint32_t inputLength = sizeof(float) * inputSize;
    130     const float kZeros[100] = {};
    131     ASSERT_GE(sizeof(kZeros), inputLength);
    132     model->setOperandValue(inputZeros, &kZeros, inputLength);
    133 
    134     ExtensionOperandType scalarType(Type::INT32, {});
    135     uint32_t activation = model->addOperand(&scalarType);
    136     int32_t kNoActivation = ANEURALNETWORKS_FUSED_NONE;
    137     model->setOperandValue(activation, &kNoActivation, sizeof(kNoActivation));
    138 
    139     model->addOperation(ANEURALNETWORKS_ADD, {input, inputZeros, activation}, {output});
    140 }
    141 
    142 void createModel(ExtensionModel* model, ExtensionOperandType inputType,
    143                  ExtensionOperandType outputType, bool addNopOperations) {
    144     uint32_t fibonacciInput = model->addOperand(&inputType);
    145     uint32_t fibonacciOutput = model->addOperand(&outputType);
    146 
    147     uint32_t modelInput = addNopOperations ? model->addOperand(&inputType) : fibonacciInput;
    148     uint32_t modelOutput = addNopOperations ? model->addOperand(&outputType) : fibonacciOutput;
    149 
    150     if (addNopOperations) {
    151         addNopOperation(model, inputType, modelInput, fibonacciInput);
    152     }
    153     model->addOperation(model->getExtensionOperationType(TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
    154                                                          TEST_VENDOR_FIBONACCI),
    155                         {fibonacciInput}, {fibonacciOutput});
    156     if (addNopOperations) {
    157         addNopOperation(model, outputType, fibonacciOutput, modelOutput);
    158     }
    159 
    160     model->identifyInputsAndOutputs({modelInput}, {modelOutput});
    161     model->finish();
    162     ASSERT_TRUE(model->isValid());
    163 }
    164 
    165 TEST_F(FibonacciExtensionTest, ModelWithExtensionOperandTypes) {
    166     constexpr uint32_t N = 10;
    167     constexpr double scale = 0.5;
    168     constexpr int64_t zeroPoint = 10;
    169 
    170     ExtensionOperandType inputType(
    171             static_cast<Type>(mModel.getExtensionOperandType(TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
    172                                                              TEST_VENDOR_INT64)),
    173             {});
    174     ExtensionOperandType outputType(
    175             static_cast<Type>(mModel.getExtensionOperandType(TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
    176                                                              TEST_VENDOR_TENSOR_QUANT64_ASYMM)),
    177             {N},
    178             ExtensionOperandParams(TestVendorQuant64AsymmParams{
    179                     .scale = scale,
    180                     .zeroPoint = zeroPoint,
    181             }));
    182     createModel(&mModel, inputType, outputType, /*addNopOperations=*/false);
    183     checkSupportedOperations({true});
    184     prepareForExecution();
    185 
    186     int64_t input = N;
    187     EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, &input, sizeof(input)),
    188               ANEURALNETWORKS_NO_ERROR);
    189 
    190     int64_t output[N] = {};
    191     EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, &output, sizeof(output)),
    192               ANEURALNETWORKS_NO_ERROR);
    193 
    194     ASSERT_EQ(ANeuralNetworksExecution_compute(mExecution), ANEURALNETWORKS_NO_ERROR);
    195 
    196     EXPECT_EQ(output[0], 1 / scale + zeroPoint);
    197     EXPECT_EQ(output[1], 1 / scale + zeroPoint);
    198     EXPECT_EQ(output[2], 2 / scale + zeroPoint);
    199     EXPECT_EQ(output[3], 3 / scale + zeroPoint);
    200     EXPECT_EQ(output[4], 5 / scale + zeroPoint);
    201     EXPECT_EQ(output[5], 8 / scale + zeroPoint);
    202     EXPECT_EQ(output[6], 13 / scale + zeroPoint);
    203     EXPECT_EQ(output[7], 21 / scale + zeroPoint);
    204     EXPECT_EQ(output[8], 34 / scale + zeroPoint);
    205     EXPECT_EQ(output[9], 55 / scale + zeroPoint);
    206 }
    207 
    208 TEST_F(FibonacciExtensionTest, ModelWithTemporaries) {
    209     constexpr uint32_t N = 10;
    210 
    211     ExtensionOperandType inputType(Type::TENSOR_FLOAT32, {1});
    212     ExtensionOperandType outputType(Type::TENSOR_FLOAT32, {N});
    213     createModel(&mModel, inputType, outputType, /*addNopOperations=*/true);
    214     checkSupportedOperations({true, true, true});
    215     prepareForExecution();
    216 
    217     float input[] = {N};
    218     EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, &input, sizeof(input)),
    219               ANEURALNETWORKS_NO_ERROR);
    220 
    221     float output[N] = {};
    222     EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, &output, sizeof(output)),
    223               ANEURALNETWORKS_NO_ERROR);
    224 
    225     ASSERT_EQ(ANeuralNetworksExecution_compute(mExecution), ANEURALNETWORKS_NO_ERROR);
    226 
    227     EXPECT_EQ(output[0], 1);
    228     EXPECT_EQ(output[1], 1);
    229     EXPECT_EQ(output[2], 2);
    230     EXPECT_EQ(output[3], 3);
    231     EXPECT_EQ(output[4], 5);
    232     EXPECT_EQ(output[5], 8);
    233     EXPECT_EQ(output[6], 13);
    234     EXPECT_EQ(output[7], 21);
    235     EXPECT_EQ(output[8], 34);
    236     EXPECT_EQ(output[9], 55);
    237 }
    238 
    239 TEST_F(FibonacciExtensionTest, InvalidInputType) {
    240     ExtensionOperandType inputType(Type::TENSOR_INT32, {1});  // Unsupported type.
    241     ExtensionOperandType outputType(Type::TENSOR_FLOAT32, {1});
    242     createModel(&mModel, inputType, outputType, /*addNopOperations=*/false);
    243     checkSupportedOperations({false});  // The driver reports that it doesn't support the operation.
    244     ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel.getHandle(), mDevices.data(),
    245                                                           mDevices.size(), &mCompilation),
    246               ANEURALNETWORKS_NO_ERROR);
    247     ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_DATA);
    248 }
    249 
    250 TEST_F(FibonacciExtensionTest, InvalidOutputType) {
    251     ExtensionOperandType inputType(Type::TENSOR_FLOAT32, {1});
    252     ExtensionOperandType outputType(Type::TENSOR_INT32, {1});  // Unsupported type.
    253     createModel(&mModel, inputType, outputType, /*addNopOperations=*/false);
    254     checkSupportedOperations({false});  // The driver reports that it doesn't support the operation.
    255     ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel.getHandle(), mDevices.data(),
    256                                                           mDevices.size(), &mCompilation),
    257               ANEURALNETWORKS_NO_ERROR);
    258     ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_DATA);
    259 }
    260 
    261 TEST_F(FibonacciExtensionTest, InvalidInputValue) {
    262     ExtensionOperandType inputType(Type::TENSOR_FLOAT32, {1});
    263     ExtensionOperandType outputType(Type::TENSOR_FLOAT32, {1});
    264     createModel(&mModel, inputType, outputType, /*addNopOperations=*/false);
    265     checkSupportedOperations({true});
    266     prepareForExecution();
    267 
    268     float input[] = {-1};  // Invalid input value.
    269     EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, &input, sizeof(input)),
    270               ANEURALNETWORKS_NO_ERROR);
    271 
    272     float output[1] = {};
    273     EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, &output, sizeof(output)),
    274               ANEURALNETWORKS_NO_ERROR);
    275 
    276     ASSERT_EQ(ANeuralNetworksExecution_compute(mExecution), ANEURALNETWORKS_OP_FAILED);
    277 }
    278 
    279 TEST_F(FibonacciExtensionTest, InvalidNumInputs) {
    280     ExtensionOperandType inputType(Type::TENSOR_FLOAT32, {1});
    281     ExtensionOperandType outputType(Type::TENSOR_FLOAT32, {1});
    282     uint32_t input1 = mModel.addOperand(&inputType);
    283     uint32_t input2 = mModel.addOperand(&inputType);  // Extra input.
    284     uint32_t output = mModel.addOperand(&outputType);
    285     mModel.addOperation(mModel.getExtensionOperationType(TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
    286                                                          TEST_VENDOR_FIBONACCI),
    287                         {input1, input2}, {output});
    288     mModel.identifyInputsAndOutputs({input1, input2}, {output});
    289     mModel.finish();
    290     ASSERT_TRUE(mModel.isValid());
    291     checkSupportedOperations({false});
    292     ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel.getHandle(), mDevices.data(),
    293                                                           mDevices.size(), &mCompilation),
    294               ANEURALNETWORKS_NO_ERROR);
    295     ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_DATA);
    296 }
    297 
    298 TEST_F(FibonacciExtensionTest, InvalidNumOutputs) {
    299     ExtensionOperandType inputType(Type::TENSOR_FLOAT32, {1});
    300     ExtensionOperandType outputType(Type::TENSOR_FLOAT32, {1});
    301     uint32_t input = mModel.addOperand(&inputType);
    302     uint32_t output1 = mModel.addOperand(&outputType);
    303     uint32_t output2 = mModel.addOperand(&outputType);  // Extra output.
    304     mModel.addOperation(mModel.getExtensionOperationType(TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
    305                                                          TEST_VENDOR_FIBONACCI),
    306                         {input}, {output1, output2});
    307     mModel.identifyInputsAndOutputs({input}, {output1, output2});
    308     mModel.finish();
    309     ASSERT_TRUE(mModel.isValid());
    310     checkSupportedOperations({false});
    311     ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel.getHandle(), mDevices.data(),
    312                                                           mDevices.size(), &mCompilation),
    313               ANEURALNETWORKS_NO_ERROR);
    314     ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_DATA);
    315 }
    316 
    317 TEST_F(FibonacciExtensionTest, InvalidOperation) {
    318     ExtensionOperandType inputType(Type::TENSOR_FLOAT32, {1});
    319     ExtensionOperandType outputType(Type::TENSOR_FLOAT32, {1});
    320     uint32_t input = mModel.addOperand(&inputType);
    321     uint32_t output = mModel.addOperand(&outputType);
    322     mModel.addOperation(mModel.getExtensionOperationType(
    323                                 TEST_VENDOR_FIBONACCI_EXTENSION_NAME,
    324                                 TEST_VENDOR_FIBONACCI + 1),  // This operation should not exist.
    325                         {input}, {output});
    326     mModel.identifyInputsAndOutputs({input}, {output});
    327     mModel.finish();
    328     ASSERT_TRUE(mModel.isValid());
    329     checkSupportedOperations({false});
    330     ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel.getHandle(), mDevices.data(),
    331                                                           mDevices.size(), &mCompilation),
    332               ANEURALNETWORKS_NO_ERROR);
    333     ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_DATA);
    334 }
    335 
    336 }  // namespace
    337 }  // namespace nn
    338 }  // namespace android
    339