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