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