Home | History | Annotate | Download | only in functional
      1 /*
      2  * Copyright (C) 2017 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 #define LOG_TAG "neuralnetworks_hidl_hal_test"
     18 
     19 #include "Models.h"
     20 #include <android/hidl/memory/1.0/IMemory.h>
     21 #include <hidlmemory/mapping.h>
     22 #include <vector>
     23 
     24 namespace android {
     25 namespace hardware {
     26 namespace neuralnetworks {
     27 namespace V1_0 {
     28 namespace vts {
     29 namespace functional {
     30 
     31 // create a valid model
     32 Model createValidTestModel() {
     33     const std::vector<float> operand2Data = {5.0f, 6.0f, 7.0f, 8.0f};
     34     const uint32_t size = operand2Data.size() * sizeof(float);
     35 
     36     const uint32_t operand1 = 0;
     37     const uint32_t operand2 = 1;
     38     const uint32_t operand3 = 2;
     39     const uint32_t operand4 = 3;
     40 
     41     const std::vector<Operand> operands = {
     42         {
     43             .type = OperandType::TENSOR_FLOAT32,
     44             .dimensions = {1, 2, 2, 1},
     45             .numberOfConsumers = 1,
     46             .scale = 0.0f,
     47             .zeroPoint = 0,
     48             .lifetime = OperandLifeTime::MODEL_INPUT,
     49             .location = {.poolIndex = 0, .offset = 0, .length = 0},
     50         },
     51         {
     52             .type = OperandType::TENSOR_FLOAT32,
     53             .dimensions = {1, 2, 2, 1},
     54             .numberOfConsumers = 1,
     55             .scale = 0.0f,
     56             .zeroPoint = 0,
     57             .lifetime = OperandLifeTime::CONSTANT_COPY,
     58             .location = {.poolIndex = 0, .offset = 0, .length = size},
     59         },
     60         {
     61             .type = OperandType::INT32,
     62             .dimensions = {},
     63             .numberOfConsumers = 1,
     64             .scale = 0.0f,
     65             .zeroPoint = 0,
     66             .lifetime = OperandLifeTime::CONSTANT_COPY,
     67             .location = {.poolIndex = 0, .offset = size, .length = sizeof(int32_t)},
     68         },
     69         {
     70             .type = OperandType::TENSOR_FLOAT32,
     71             .dimensions = {1, 2, 2, 1},
     72             .numberOfConsumers = 0,
     73             .scale = 0.0f,
     74             .zeroPoint = 0,
     75             .lifetime = OperandLifeTime::MODEL_OUTPUT,
     76             .location = {.poolIndex = 0, .offset = 0, .length = 0},
     77         },
     78     };
     79 
     80     const std::vector<Operation> operations = {{
     81         .type = OperationType::ADD, .inputs = {operand1, operand2, operand3}, .outputs = {operand4},
     82     }};
     83 
     84     const std::vector<uint32_t> inputIndexes = {operand1};
     85     const std::vector<uint32_t> outputIndexes = {operand4};
     86     std::vector<uint8_t> operandValues(
     87         reinterpret_cast<const uint8_t*>(operand2Data.data()),
     88         reinterpret_cast<const uint8_t*>(operand2Data.data()) + size);
     89     int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
     90     operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
     91                          reinterpret_cast<const uint8_t*>(&activation[1]));
     92 
     93     const std::vector<hidl_memory> pools = {};
     94 
     95     return {
     96         .operands = operands,
     97         .operations = operations,
     98         .inputIndexes = inputIndexes,
     99         .outputIndexes = outputIndexes,
    100         .operandValues = operandValues,
    101         .pools = pools,
    102     };
    103 }
    104 
    105 // create first invalid model
    106 Model createInvalidTestModel1() {
    107     Model model = createValidTestModel();
    108     model.operations[0].type = static_cast<OperationType>(0xDEADBEEF); /* INVALID */
    109     return model;
    110 }
    111 
    112 // create second invalid model
    113 Model createInvalidTestModel2() {
    114     Model model = createValidTestModel();
    115     const uint32_t operand1 = 0;
    116     const uint32_t operand5 = 4;  // INVALID OPERAND
    117     model.inputIndexes = std::vector<uint32_t>({operand1, operand5 /* INVALID OPERAND */});
    118     return model;
    119 }
    120 
    121 // allocator helper
    122 hidl_memory allocateSharedMemory(int64_t size, const std::string& type = "ashmem") {
    123     hidl_memory memory;
    124 
    125     sp<IAllocator> allocator = IAllocator::getService(type);
    126     if (!allocator.get()) {
    127         return {};
    128     }
    129 
    130     Return<void> ret = allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
    131         ASSERT_TRUE(success);
    132         memory = mem;
    133     });
    134     if (!ret.isOk()) {
    135         return {};
    136     }
    137 
    138     return memory;
    139 }
    140 
    141 // create a valid request
    142 Request createValidTestRequest() {
    143     std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
    144     std::vector<float> outputData = {-1.0f, -1.0f, -1.0f, -1.0f};
    145     const uint32_t INPUT = 0;
    146     const uint32_t OUTPUT = 1;
    147 
    148     // prepare inputs
    149     uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
    150     uint32_t outputSize = static_cast<uint32_t>(outputData.size() * sizeof(float));
    151     std::vector<RequestArgument> inputs = {{
    152         .location = {.poolIndex = INPUT, .offset = 0, .length = inputSize}, .dimensions = {},
    153     }};
    154     std::vector<RequestArgument> outputs = {{
    155         .location = {.poolIndex = OUTPUT, .offset = 0, .length = outputSize}, .dimensions = {},
    156     }};
    157     std::vector<hidl_memory> pools = {allocateSharedMemory(inputSize),
    158                                       allocateSharedMemory(outputSize)};
    159     if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
    160         return {};
    161     }
    162 
    163     // load data
    164     sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
    165     sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
    166     if (inputMemory.get() == nullptr || outputMemory.get() == nullptr) {
    167         return {};
    168     }
    169     float* inputPtr = reinterpret_cast<float*>(static_cast<void*>(inputMemory->getPointer()));
    170     float* outputPtr = reinterpret_cast<float*>(static_cast<void*>(outputMemory->getPointer()));
    171     if (inputPtr == nullptr || outputPtr == nullptr) {
    172         return {};
    173     }
    174     inputMemory->update();
    175     outputMemory->update();
    176     std::copy(inputData.begin(), inputData.end(), inputPtr);
    177     std::copy(outputData.begin(), outputData.end(), outputPtr);
    178     inputMemory->commit();
    179     outputMemory->commit();
    180 
    181     return {.inputs = inputs, .outputs = outputs, .pools = pools};
    182 }
    183 
    184 // create first invalid request
    185 Request createInvalidTestRequest1() {
    186     Request request = createValidTestRequest();
    187     const uint32_t INVALID = 2;
    188     std::vector<float> inputData = {1.0f, 2.0f, 3.0f, 4.0f};
    189     uint32_t inputSize = static_cast<uint32_t>(inputData.size() * sizeof(float));
    190     request.inputs[0].location = {
    191         .poolIndex = INVALID /* INVALID */, .offset = 0, .length = inputSize};
    192     return request;
    193 }
    194 
    195 // create second invalid request
    196 Request createInvalidTestRequest2() {
    197     Request request = createValidTestRequest();
    198     request.inputs[0].dimensions = std::vector<uint32_t>({1, 2, 3, 4, 5, 6, 7, 8} /* INVALID */);
    199     return request;
    200 }
    201 
    202 }  // namespace functional
    203 }  // namespace vts
    204 }  // namespace V1_0
    205 }  // namespace neuralnetworks
    206 }  // namespace hardware
    207 }  // namespace android
    208