blob: 678f16b3d24babf2982f2ddee38700a972806599 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include "HalInterfaces.h"
#include "ModelBuilder.h"
#include "TestGenerated.h"
#include "TestNeuralNetworksWrapper.h"
#include "Utils.h"
namespace android::nn::compliance_test {
using namespace hal;
using namespace test_helper;
using HidlModel = V1_3::Model;
using WrapperModel = test_wrapper::Model;
using WrapperOperandType = test_wrapper::OperandType;
using WrapperType = test_wrapper::Type;
// Tag for the compilance tests
class ComplianceTest : public ::testing::Test {};
// Creates a HIDL model from a creator of the wrapper model.
static HidlModel createHidlModel(std::function<void(WrapperModel*)> createModel) {
WrapperModel wrapperModel;
createModel(&wrapperModel);
EXPECT_EQ(wrapperModel.finish(), test_wrapper::Result::NO_ERROR);
ModelBuilder* modelBuilder = reinterpret_cast<ModelBuilder*>(wrapperModel.getHandle());
return modelBuilder->makeHidlModel();
}
void testAvailableSinceV1_3(std::function<void(WrapperModel*)> createModel) {
HidlModel model = createHidlModel(createModel);
ASSERT_FALSE(compliantWithV1_2(model));
ASSERT_FALSE(compliantWithV1_1(model));
ASSERT_FALSE(compliantWithV1_0(model));
}
void testAvailableSinceV1_2(std::function<void(WrapperModel*)> createModel) {
HidlModel model = createHidlModel(createModel);
ASSERT_TRUE(compliantWithV1_2(model));
ASSERT_FALSE(compliantWithV1_1(model));
ASSERT_FALSE(compliantWithV1_0(model));
}
void testAvailableSinceV1_1(std::function<void(WrapperModel*)> createModel) {
HidlModel model = createHidlModel(createModel);
ASSERT_TRUE(compliantWithV1_2(model));
ASSERT_TRUE(compliantWithV1_1(model));
ASSERT_FALSE(compliantWithV1_0(model));
}
void testAvailableSinceV1_0(std::function<void(WrapperModel*)> createModel) {
HidlModel model = createHidlModel(createModel);
ASSERT_TRUE(compliantWithV1_2(model));
ASSERT_TRUE(compliantWithV1_1(model));
ASSERT_TRUE(compliantWithV1_0(model));
}
static const WrapperOperandType kTypeTensorFloat(WrapperType::TENSOR_FLOAT32, {1});
static const WrapperOperandType kTypeTensorFloatRank0(WrapperType::TENSOR_FLOAT32, {});
static const WrapperOperandType kTypeInt32(WrapperType::INT32, {});
TEST_F(ComplianceTest, Rank0TensorModelInput) {
int32_t act_init = 0;
// A simple ADD operation: op1 ADD op2 = op3, with op1 and op2 of rank 0.
testAvailableSinceV1_2([&act_init](WrapperModel* model) {
auto op1 = model->addOperand(&kTypeTensorFloatRank0);
auto op2 = model->addOperand(&kTypeTensorFloatRank0);
auto act = model->addOperand(&kTypeInt32);
auto op3 = model->addOperand(&kTypeTensorFloat);
model->setOperandValue(act, &act_init, sizeof(act_init));
model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
model->identifyInputsAndOutputs({op1, op2}, {op3});
assert(model->isValid());
});
}
TEST_F(ComplianceTest, Rank0TensorModelOutput) {
int32_t act_init = 0;
// A simple ADD operation: op1 ADD op2 = op3, with op3 of rank 0.
testAvailableSinceV1_2([&act_init](WrapperModel* model) {
auto op1 = model->addOperand(&kTypeTensorFloat);
auto op2 = model->addOperand(&kTypeTensorFloat);
auto act = model->addOperand(&kTypeInt32);
auto op3 = model->addOperand(&kTypeTensorFloatRank0);
model->setOperandValue(act, &act_init, sizeof(act_init));
model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
model->identifyInputsAndOutputs({op1, op2}, {op3});
assert(model->isValid());
});
}
TEST_F(ComplianceTest, Rank0TensorTemporaryVariable) {
int32_t act_init = 0;
// Two ADD operations: op1 ADD op2 = op3, op3 ADD op4 = op5, with op3 of rank 0.
testAvailableSinceV1_2([&act_init](WrapperModel* model) {
auto op1 = model->addOperand(&kTypeTensorFloat);
auto op2 = model->addOperand(&kTypeTensorFloat);
auto op3 = model->addOperand(&kTypeTensorFloatRank0);
auto op4 = model->addOperand(&kTypeTensorFloat);
auto op5 = model->addOperand(&kTypeTensorFloat);
auto act = model->addOperand(&kTypeInt32);
model->setOperandValue(act, &act_init, sizeof(act_init));
model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
model->addOperation(ANEURALNETWORKS_ADD, {op3, op4, act}, {op5});
model->identifyInputsAndOutputs({op1, op2, op4}, {op5});
assert(model->isValid());
});
}
TEST_F(ComplianceTest, HardwareBuffer) {
const size_t memorySize = 20;
AHardwareBuffer_Desc desc{
.width = memorySize,
.height = 1,
.layers = 1,
.format = AHARDWAREBUFFER_FORMAT_BLOB,
.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
};
AHardwareBuffer* buffer = nullptr;
ASSERT_EQ(AHardwareBuffer_allocate(&desc, &buffer), 0);
test_wrapper::Memory memory(buffer);
ASSERT_TRUE(memory.isValid());
int32_t act_init = 0;
// A simple ADD operation: op1 ADD op2 = op3, with op2 using a const hardware buffer.
testAvailableSinceV1_2([&memory, &act_init](WrapperModel* model) {
auto op1 = model->addOperand(&kTypeTensorFloat);
auto op2 = model->addOperand(&kTypeTensorFloat);
auto act = model->addOperand(&kTypeInt32);
auto op3 = model->addOperand(&kTypeTensorFloat);
model->setOperandValueFromMemory(op2, &memory, 0, sizeof(float));
model->setOperandValue(act, &act_init, sizeof(act_init));
model->addOperation(ANEURALNETWORKS_ADD, {op1, op2, act}, {op3});
model->identifyInputsAndOutputs({op1}, {op3});
assert(model->isValid());
});
AHardwareBuffer_release(buffer);
}
class GeneratedComplianceTest : public generated_tests::GeneratedTestBase {};
TEST_P(GeneratedComplianceTest, Test) {
const auto createModel = [this](WrapperModel* model) {
generated_tests::createModel(testModel, model);
};
switch (testModel.minSupportedVersion) {
case TestHalVersion::V1_0:
testAvailableSinceV1_0(createModel);
break;
case TestHalVersion::V1_1:
testAvailableSinceV1_1(createModel);
break;
case TestHalVersion::V1_2:
testAvailableSinceV1_2(createModel);
break;
case TestHalVersion::V1_3:
testAvailableSinceV1_3(createModel);
break;
case TestHalVersion::UNKNOWN:
FAIL();
}
}
INSTANTIATE_GENERATED_TEST(GeneratedComplianceTest, [](const TestModel& testModel) {
return !testModel.expectFailure && testModel.minSupportedVersion != TestHalVersion::UNKNOWN;
});
} // namespace android::nn::compliance_test