| // |
| // Copyright © 2017 Arm Ltd. All rights reserved. |
| // SPDX-License-Identifier: MIT |
| // |
| #include "DriverTestHelpers.hpp" |
| |
| #include "../1.0/HalPolicy.hpp" |
| |
| #include <boost/test/unit_test.hpp> |
| |
| #include <log/log.h> |
| |
| BOOST_AUTO_TEST_SUITE(GenericLayerTests) |
| |
| using namespace android::hardware; |
| using namespace driverTestHelpers; |
| using namespace armnn_driver; |
| |
| using HalPolicy = hal_1_0::HalPolicy; |
| |
| BOOST_AUTO_TEST_CASE(GetSupportedOperations) |
| { |
| auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); |
| |
| V1_0::ErrorStatus errorStatus; |
| std::vector<bool> supported; |
| |
| auto cb = [&](V1_0::ErrorStatus _errorStatus, const std::vector<bool>& _supported) |
| { |
| errorStatus = _errorStatus; |
| supported = _supported; |
| }; |
| |
| HalPolicy::Model model0 = {}; |
| |
| // Add operands |
| int32_t actValue = 0; |
| float weightValue[] = {2, 4, 1}; |
| float biasValue[] = {4}; |
| |
| AddInputOperand<HalPolicy>(model0, hidl_vec<uint32_t>{1, 3}); |
| AddTensorOperand<HalPolicy>(model0, hidl_vec<uint32_t>{1, 3}, weightValue); |
| AddTensorOperand<HalPolicy>(model0, hidl_vec<uint32_t>{1}, biasValue); |
| AddIntOperand<HalPolicy>(model0, actValue); |
| AddOutputOperand<HalPolicy>(model0, hidl_vec<uint32_t>{1, 1}); |
| |
| model0.operations.resize(1); |
| |
| // Make a correct fully connected operation |
| model0.operations[0].type = HalPolicy::OperationType::FULLY_CONNECTED; |
| model0.operations[0].inputs = hidl_vec<uint32_t>{0, 1, 2, 3}; |
| model0.operations[0].outputs = hidl_vec<uint32_t>{4}; |
| |
| driver->getSupportedOperations(model0, cb); |
| BOOST_TEST((int)errorStatus == (int)V1_0::ErrorStatus::NONE); |
| BOOST_TEST(supported.size() == (size_t)1); |
| BOOST_TEST(supported[0] == true); |
| |
| V1_0::Model model1 = {}; |
| |
| AddInputOperand<HalPolicy>(model1, hidl_vec<uint32_t>{1, 3}); |
| AddTensorOperand<HalPolicy>(model1, hidl_vec<uint32_t>{1, 3}, weightValue); |
| AddTensorOperand<HalPolicy>(model1, hidl_vec<uint32_t>{1}, biasValue); |
| AddIntOperand<HalPolicy>(model1, actValue); |
| AddOutputOperand<HalPolicy>(model1, hidl_vec<uint32_t>{1, 1}); |
| |
| model1.operations.resize(2); |
| |
| // Make a correct fully connected operation |
| model1.operations[0].type = HalPolicy::OperationType::FULLY_CONNECTED; |
| model1.operations[0].inputs = hidl_vec<uint32_t>{0, 1, 2, 3}; |
| model1.operations[0].outputs = hidl_vec<uint32_t>{4}; |
| |
| // Add an incorrect fully connected operation |
| AddIntOperand<HalPolicy>(model1, actValue); |
| AddOutputOperand<HalPolicy>(model1, hidl_vec<uint32_t>{1, 1}); |
| |
| model1.operations[1].type = HalPolicy::OperationType::FULLY_CONNECTED; |
| model1.operations[1].inputs = hidl_vec<uint32_t>{4}; // Only 1 input operand, expected 4 |
| model1.operations[1].outputs = hidl_vec<uint32_t>{5}; |
| |
| driver->getSupportedOperations(model1, cb); |
| |
| BOOST_TEST((int)errorStatus == (int)V1_0::ErrorStatus::INVALID_ARGUMENT); |
| BOOST_TEST(supported.empty()); |
| |
| // Test Broadcast on add/mul operators |
| HalPolicy::Model model2 = {}; |
| |
| AddInputOperand<HalPolicy>(model2, |
| hidl_vec<uint32_t>{1, 1, 3, 4}, |
| HalPolicy::OperandType::TENSOR_FLOAT32, |
| 0.0f, |
| 0, |
| 2); |
| AddInputOperand<HalPolicy>(model2, |
| hidl_vec<uint32_t>{4}, |
| HalPolicy::OperandType::TENSOR_FLOAT32, |
| 0.0f, |
| 0, |
| 2); |
| AddIntOperand<HalPolicy>(model2, actValue, 2); |
| AddOutputOperand<HalPolicy>(model2, hidl_vec<uint32_t>{1, 1, 3, 4}); |
| AddOutputOperand<HalPolicy>(model2, hidl_vec<uint32_t>{1, 1, 3, 4}); |
| |
| model2.operations.resize(2); |
| |
| model2.operations[0].type = HalPolicy::OperationType::ADD; |
| model2.operations[0].inputs = hidl_vec<uint32_t>{0, 1, 2}; |
| model2.operations[0].outputs = hidl_vec<uint32_t>{3}; |
| |
| model2.operations[1].type = HalPolicy::OperationType::MUL; |
| model2.operations[1].inputs = hidl_vec<uint32_t>{0, 1, 2}; |
| model2.operations[1].outputs = hidl_vec<uint32_t>{4}; |
| |
| driver->getSupportedOperations(model2, cb); |
| BOOST_TEST((int)errorStatus == (int)V1_0::ErrorStatus::NONE); |
| BOOST_TEST(supported.size() == (size_t)2); |
| BOOST_TEST(supported[0] == true); |
| BOOST_TEST(supported[1] == true); |
| |
| V1_0::Model model3 = {}; |
| |
| AddInputOperand<HalPolicy>(model3, |
| hidl_vec<uint32_t>{1, 1, 3, 4}, |
| HalPolicy::OperandType::TENSOR_INT32); |
| AddInputOperand<HalPolicy>(model3, |
| hidl_vec<uint32_t>{4}, |
| HalPolicy::OperandType::TENSOR_INT32); |
| AddInputOperand<HalPolicy>(model3, hidl_vec<uint32_t>{1, 1, 3, 4}); |
| |
| AddOutputOperand<HalPolicy>(model3, hidl_vec<uint32_t>{1, 1, 3, 4}); |
| AddOutputOperand<HalPolicy>(model3, |
| hidl_vec<uint32_t>{1, 1, 3, 4}, |
| HalPolicy::OperandType::TENSOR_QUANT8_ASYMM, |
| 1.f / 225.f); |
| |
| model3.operations.resize(1); |
| |
| // Add unsupported operation, should return no error but we don't support it |
| model3.operations[0].type = HalPolicy::OperationType::HASHTABLE_LOOKUP; |
| model3.operations[0].inputs = hidl_vec<uint32_t>{0, 1, 2}; |
| model3.operations[0].outputs = hidl_vec<uint32_t>{3, 4}; |
| |
| driver->getSupportedOperations(model3, cb); |
| BOOST_TEST((int)errorStatus == (int)V1_0::ErrorStatus::NONE); |
| BOOST_TEST(supported.size() == (size_t)1); |
| BOOST_TEST(supported[0] == false); |
| |
| HalPolicy::Model model4 = {}; |
| |
| AddIntOperand<HalPolicy>(model4, 0); |
| |
| model4.operations.resize(1); |
| |
| // Add invalid operation |
| model4.operations[0].type = static_cast<HalPolicy::OperationType>(100); |
| model4.operations[0].outputs = hidl_vec<uint32_t>{0}; |
| |
| driver->getSupportedOperations(model4, cb); |
| BOOST_TEST((int)errorStatus == (int)V1_0::ErrorStatus::INVALID_ARGUMENT); |
| BOOST_TEST(supported.empty()); |
| } |
| |
| // The purpose of this test is to ensure that when encountering an unsupported operation |
| // it is skipped and getSupportedOperations() continues (rather than failing and stopping). |
| // As per IVGCVSW-710. |
| BOOST_AUTO_TEST_CASE(UnsupportedLayerContinueOnFailure) |
| { |
| auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); |
| |
| V1_0::ErrorStatus errorStatus; |
| std::vector<bool> supported; |
| |
| auto cb = [&](V1_0::ErrorStatus _errorStatus, const std::vector<bool>& _supported) |
| { |
| errorStatus = _errorStatus; |
| supported = _supported; |
| }; |
| |
| HalPolicy::Model model = {}; |
| |
| // Operands |
| int32_t actValue = 0; |
| float weightValue[] = {2, 4, 1}; |
| float biasValue[] = {4}; |
| |
| // HASHTABLE_LOOKUP is unsupported at the time of writing this test, but any unsupported layer will do |
| AddInputOperand<HalPolicy>(model, |
| hidl_vec<uint32_t>{1, 1, 3, 4}, |
| HalPolicy::OperandType::TENSOR_INT32); |
| AddInputOperand<HalPolicy>(model, |
| hidl_vec<uint32_t>{4}, |
| HalPolicy::OperandType::TENSOR_INT32, |
| 0.0f, |
| 0, |
| 2); |
| AddInputOperand<HalPolicy>(model, |
| hidl_vec<uint32_t>{1, 1, 3, 4}, |
| HalPolicy::OperandType::TENSOR_FLOAT32, |
| 0.0f, |
| 0, |
| 2); |
| |
| AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 1, 3, 4}); |
| AddOutputOperand<HalPolicy>(model, |
| hidl_vec<uint32_t>{1, 1, 3, 4}, |
| HalPolicy::OperandType::TENSOR_QUANT8_ASYMM, |
| 1.f / 225.f); |
| |
| // Fully connected is supported |
| AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 3}); |
| |
| AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 3}, weightValue); |
| AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{1}, biasValue); |
| |
| AddIntOperand<HalPolicy>(model, actValue); |
| |
| AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 1}); |
| |
| // EMBEDDING_LOOKUP is unsupported |
| AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 1, 3, 4}); |
| |
| model.operations.resize(3); |
| |
| // Unsupported |
| model.operations[0].type = HalPolicy::OperationType::HASHTABLE_LOOKUP; |
| model.operations[0].inputs = hidl_vec<uint32_t>{0, 1, 2}; |
| model.operations[0].outputs = hidl_vec<uint32_t>{3, 4}; |
| |
| // Supported |
| model.operations[1].type = HalPolicy::OperationType::FULLY_CONNECTED; |
| model.operations[1].inputs = hidl_vec<uint32_t>{5, 6, 7, 8}; |
| model.operations[1].outputs = hidl_vec<uint32_t>{9}; |
| |
| // Unsupported |
| model.operations[2].type = HalPolicy::OperationType::EMBEDDING_LOOKUP; |
| model.operations[2].inputs = hidl_vec<uint32_t>{1, 2}; |
| model.operations[2].outputs = hidl_vec<uint32_t>{10}; |
| |
| // We are testing that the unsupported layers return false and the test continues rather than failing and stopping |
| driver->getSupportedOperations(model, cb); |
| BOOST_TEST((int)errorStatus == (int)V1_0::ErrorStatus::NONE); |
| BOOST_TEST(supported.size() == (size_t)3); |
| BOOST_TEST(supported[0] == false); |
| BOOST_TEST(supported[1] == true); |
| BOOST_TEST(supported[2] == false); |
| } |
| |
| // The purpose of this test is to ensure that when encountering an failure |
| // during mem pool mapping we properly report an error to the framework via a callback |
| BOOST_AUTO_TEST_CASE(ModelToINetworkConverterMemPoolFail) |
| { |
| auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); |
| |
| V1_0::ErrorStatus errorStatus; |
| std::vector<bool> supported; |
| |
| auto cb = [&](V1_0::ErrorStatus _errorStatus, const std::vector<bool>& _supported) |
| { |
| errorStatus = _errorStatus; |
| supported = _supported; |
| }; |
| |
| HalPolicy::Model model = {}; |
| |
| model.pools = hidl_vec<hidl_memory>{hidl_memory("Unsuported hidl memory type", nullptr, 0)}; |
| |
| // Memory pool mapping should fail, we should report an error |
| driver->getSupportedOperations(model, cb); |
| BOOST_TEST((int)errorStatus != (int)V1_0::ErrorStatus::NONE); |
| BOOST_TEST(supported.empty()); |
| } |
| |
| BOOST_AUTO_TEST_SUITE_END() |