4224 lines
192 KiB
C++
4224 lines
192 KiB
C++
/*
|
|
* Copyright (C) 2017 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 <android-base/logging.h>
|
|
#include <android-base/scopeguard.h>
|
|
// android/log.h contains __INTRODUCED_IN() macro and must be included before
|
|
// sharedmem.h
|
|
#include <android/log.h>
|
|
#include <android/sharedmem.h>
|
|
#include <gtest/gtest.h>
|
|
#include <sys/mman.h>
|
|
|
|
#include <algorithm>
|
|
#include <future>
|
|
#include <limits>
|
|
#include <set>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "AndroidVersionUtil.h"
|
|
#include "NeuralNetworks.h"
|
|
#include "NeuralNetworksOEM.h"
|
|
#include "TmpDirectoryUtils.h"
|
|
|
|
#ifdef __ANDROID__
|
|
#include <android/hardware_buffer.h>
|
|
#else // __ANDROID__
|
|
#include <android-base/file.h>
|
|
#endif // __ANDROID__
|
|
|
|
#ifndef NNTEST_ONLY_PUBLIC_API
|
|
#include "NeuralNetworksExtensions.h"
|
|
#include "TypeManager.h"
|
|
#endif
|
|
|
|
// This file tests all the validations done by the Neural Networks API.
|
|
|
|
namespace {
|
|
|
|
constexpr uint64_t kShortWaitInNanoseconds = 1'000'000'000; // 1 second
|
|
|
|
class ValidationTest : public ::testing::Test {
|
|
protected:
|
|
virtual void SetUp() {}
|
|
};
|
|
|
|
class ValidationTestModel : public ValidationTest {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTest::SetUp();
|
|
ASSERT_EQ(ANeuralNetworksModel_create(&mModel), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
virtual void TearDown() {
|
|
ANeuralNetworksModel_free(mModel);
|
|
ValidationTest::TearDown();
|
|
}
|
|
|
|
uint32_t addScalarOperand(int32_t type = ANEURALNETWORKS_INT32) {
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = type, .dimensionCount = 0, .dimensions = nullptr};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_NO_ERROR);
|
|
return mNumOperands++;
|
|
}
|
|
|
|
uint32_t addOperand(const ANeuralNetworksOperandType& operandType) {
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_NO_ERROR);
|
|
return mNumOperands++;
|
|
}
|
|
|
|
uint32_t addTensorOperand(int32_t type = ANEURALNETWORKS_TENSOR_FLOAT32) {
|
|
return addTensorOperand(type, {2});
|
|
}
|
|
|
|
uint32_t addTensorOperand(int32_t type, const std::vector<uint32_t>& dimensions) {
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = type,
|
|
.dimensionCount = static_cast<uint32_t>(dimensions.size()),
|
|
.dimensions = dimensions.data(),
|
|
};
|
|
return addOperand(operandType);
|
|
}
|
|
|
|
int addOperation(ANeuralNetworksOperationType type, const std::vector<uint32_t>& inputs,
|
|
const std::vector<uint32_t>& outputs) {
|
|
++mNumOperations;
|
|
return ANeuralNetworksModel_addOperation(mModel, type, inputs.size(), inputs.data(),
|
|
outputs.size(), outputs.data());
|
|
}
|
|
int identifyInputsAndOutputs(const std::vector<uint32_t>& inputs,
|
|
const std::vector<uint32_t>& outputs) {
|
|
return ANeuralNetworksModel_identifyInputsAndOutputs(mModel, inputs.size(), inputs.data(),
|
|
outputs.size(), outputs.data());
|
|
}
|
|
int modelFinish() { return ANeuralNetworksModel_finish(mModel); }
|
|
|
|
virtual void createModel() {
|
|
addTensorOperand();
|
|
addTensorOperand();
|
|
addScalarOperand();
|
|
addTensorOperand();
|
|
const std::vector<uint32_t> inList = {0, 1, 2};
|
|
const std::vector<uint32_t> outList = {3};
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ADD, inList, outList), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs(inList, outList), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
uint32_t mNumOperands = 0;
|
|
uint32_t mNumOperations = 0;
|
|
ANeuralNetworksModel* mModel = nullptr;
|
|
|
|
const uint32_t kDummyDimensionValue = 1;
|
|
const ANeuralNetworksOperandType kInvalidTensorType1{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
// dimensionCount must be consistent with dimensions.
|
|
.dimensionCount = 1,
|
|
.dimensions = nullptr,
|
|
};
|
|
const ANeuralNetworksOperandType kInvalidTensorType2{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
// dimensionCount must be consistent with dimensions.
|
|
.dimensionCount = 0,
|
|
.dimensions = &kDummyDimensionValue,
|
|
};
|
|
};
|
|
|
|
#ifndef NNTEST_ONLY_PUBLIC_API
|
|
constexpr const char* kTestExtensionName = "com.android.test_extension";
|
|
constexpr int32_t kTestExtensionTensorType = ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL;
|
|
|
|
class ValidationTestModelExtensions : public ValidationTestModel {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestModel::SetUp();
|
|
EXPECT_TRUE(::android::nn::TypeManager::get()->forTest_registerExtension({
|
|
.name = kTestExtensionName,
|
|
.operandTypes =
|
|
{
|
|
{
|
|
.type = kTestExtensionTensorType,
|
|
.isTensor = true,
|
|
.byteSize = 1,
|
|
},
|
|
},
|
|
}));
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
::android::nn::TypeManager::get()->forTest_reset();
|
|
ValidationTestModel::TearDown();
|
|
}
|
|
|
|
int32_t getExtensionOperandType(uint16_t typeWithinExtension) {
|
|
int32_t result;
|
|
EXPECT_EQ(ANeuralNetworksModel_getExtensionOperandType(mModel, kTestExtensionName,
|
|
typeWithinExtension, &result),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
return result;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
class ValidationTestIdentify : public ValidationTestModel {
|
|
virtual void SetUp() {
|
|
ValidationTestModel::SetUp();
|
|
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType tensorType{.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = 1,
|
|
.dimensions = dimensions};
|
|
ANeuralNetworksOperandType scalarType{
|
|
.type = ANEURALNETWORKS_INT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ADD, {0, 1, 2}, {3}), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
virtual void TearDown() { ValidationTestModel::TearDown(); }
|
|
};
|
|
|
|
class ValidationTestCompilation : public ValidationTestModel {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestModel::SetUp();
|
|
createModel();
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mModel, &mCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
ANeuralNetworksCompilation_free(mCompilation);
|
|
ValidationTestModel::TearDown();
|
|
}
|
|
|
|
ANeuralNetworksCompilation* mCompilation = nullptr;
|
|
};
|
|
|
|
class ValidationTestExecution : public ValidationTestCompilation {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestCompilation::SetUp();
|
|
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &mExecution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
virtual void TearDown() {
|
|
ANeuralNetworksExecution_free(mExecution);
|
|
ValidationTestCompilation::TearDown();
|
|
}
|
|
ANeuralNetworksExecution* mExecution = nullptr;
|
|
};
|
|
|
|
class ValidationTestBurst : public ValidationTestExecution {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestExecution::SetUp();
|
|
|
|
ASSERT_EQ(ANeuralNetworksBurst_create(mCompilation, &mBurst), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
virtual void TearDown() {
|
|
ANeuralNetworksBurst_free(mBurst);
|
|
ValidationTestExecution::TearDown();
|
|
}
|
|
ANeuralNetworksBurst* mBurst = nullptr;
|
|
};
|
|
|
|
class ValidationTestMemoryDesc : public ValidationTestCompilation {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestCompilation::SetUp();
|
|
ASSERT_EQ(ANeuralNetworksMemoryDesc_create(&mDesc), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
virtual void TearDown() {
|
|
ANeuralNetworksMemoryDesc_free(mDesc);
|
|
for (auto* memory : mMemories) ANeuralNetworksMemory_free(memory);
|
|
for (int fd : mFds) close(fd);
|
|
ValidationTestCompilation::TearDown();
|
|
}
|
|
|
|
ANeuralNetworksMemory* createAshmem(uint32_t size) {
|
|
#ifdef __ANDROID__
|
|
int fd = ASharedMemory_create("nnMemory", size);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int fd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(fd, size), 0);
|
|
#endif // __ANDROID__
|
|
EXPECT_GT(fd, 0);
|
|
mFds.push_back(fd);
|
|
ANeuralNetworksMemory* ashmem = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(size, PROT_READ | PROT_WRITE, fd, 0, &ashmem),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
mMemories.push_back(ashmem);
|
|
return ashmem;
|
|
}
|
|
|
|
ANeuralNetworksMemoryDesc* mDesc = nullptr;
|
|
std::vector<ANeuralNetworksMemory*> mMemories;
|
|
std::vector<int> mFds;
|
|
};
|
|
|
|
class ValidationTestExecutionDeviceMemory : public ValidationTest {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTest::SetUp();
|
|
ASSERT_EQ(ANeuralNetworksModel_create(&mModel), ANEURALNETWORKS_NO_ERROR);
|
|
createModel(mModel, /*dimensionsUnspecified=*/false, /*isValid=*/true);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mModel, &mCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &mExecution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(ANeuralNetworksModel_create(&mModelDynamic), ANEURALNETWORKS_NO_ERROR);
|
|
createModel(mModelDynamic, /*dimensionsUnspecified=*/true, /*isValid=*/true);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mModelDynamic, &mCompilationDynamic),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilationDynamic), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilationDynamic, &mExecutionDynamic),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(ANeuralNetworksModel_create(&mInitModel), ANEURALNETWORKS_NO_ERROR);
|
|
createModel(mInitModel, /*dimensionsUnspecified=*/false, /*isValid=*/true);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mInitModel, &mInitCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mInitCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(ANeuralNetworksModel_create(&mDeinitModel), ANEURALNETWORKS_NO_ERROR);
|
|
createModel(mDeinitModel, /*dimensionsUnspecified=*/false, /*isValid=*/false);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mDeinitModel, &mDeinitCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mDeinitCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
virtual void TearDown() {
|
|
ANeuralNetworksExecution_free(mExecution);
|
|
ANeuralNetworksCompilation_free(mCompilation);
|
|
ANeuralNetworksModel_free(mModel);
|
|
ANeuralNetworksExecution_free(mExecutionDynamic);
|
|
ANeuralNetworksCompilation_free(mCompilationDynamic);
|
|
ANeuralNetworksModel_free(mModelDynamic);
|
|
|
|
ANeuralNetworksCompilation_free(mInitCompilation);
|
|
ANeuralNetworksModel_free(mInitModel);
|
|
ANeuralNetworksCompilation_free(mDeinitCompilation);
|
|
ANeuralNetworksModel_free(mDeinitModel);
|
|
|
|
ValidationTest::TearDown();
|
|
}
|
|
|
|
void addScalarOperand(ANeuralNetworksModel* model) {
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = ANEURALNETWORKS_INT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &operandType), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
void addTensorOperand(ANeuralNetworksModel* model, bool dimensionsUnspecified) {
|
|
uint32_t dimension = dimensionsUnspecified ? 0 : 1;
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = 1,
|
|
.dimensions = &dimension,
|
|
};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &operandType), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
void createModel(ANeuralNetworksModel* model, bool dimensionsUnspecified, bool isValid) {
|
|
const float constData = 0;
|
|
const uint32_t actData = isValid ? 0 : 999;
|
|
|
|
addTensorOperand(model, dimensionsUnspecified);
|
|
addTensorOperand(model, /*dimensionsUnspecified=*/false);
|
|
addScalarOperand(model);
|
|
addTensorOperand(model, dimensionsUnspecified);
|
|
|
|
ASSERT_EQ(ANeuralNetworksModel_setOperandValue(model, 1, &constData, sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_setOperandValue(model, 2, &actData, sizeof(uint32_t)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
uint32_t inList[] = {0, 1, 2}, outList[] = {3};
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_ADD, 3, inList, 1,
|
|
outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
uint32_t inputList[] = {0}, outputList[] = {3};
|
|
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(model, 1, inputList, 1, outputList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_finish(model), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
void executeWithMemoryAsInput(ANeuralNetworksCompilation* compilation,
|
|
ANeuralNetworksMemory* memory, int expectedResult) {
|
|
float data = 0;
|
|
ANeuralNetworksExecution* execution = nullptr;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(compilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInputFromMemory(execution, 0, nullptr, memory, 0, 0),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &data, sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), expectedResult);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
void executeWithMemoryAsOutput(ANeuralNetworksCompilation* compilation,
|
|
ANeuralNetworksMemory* memory, int expectedResult) {
|
|
const float data = 0;
|
|
ANeuralNetworksExecution* execution = nullptr;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(compilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &data, sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0, 0),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), expectedResult);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
ANeuralNetworksModel* mModel = nullptr;
|
|
ANeuralNetworksCompilation* mCompilation = nullptr;
|
|
ANeuralNetworksExecution* mExecution = nullptr;
|
|
|
|
ANeuralNetworksModel* mModelDynamic = nullptr;
|
|
ANeuralNetworksCompilation* mCompilationDynamic = nullptr;
|
|
ANeuralNetworksExecution* mExecutionDynamic = nullptr;
|
|
|
|
ANeuralNetworksModel* mInitModel = nullptr;
|
|
ANeuralNetworksCompilation* mInitCompilation = nullptr;
|
|
ANeuralNetworksModel* mDeinitModel = nullptr;
|
|
ANeuralNetworksCompilation* mDeinitCompilation = nullptr;
|
|
};
|
|
|
|
TEST_F(ValidationTest, CreateModel) {
|
|
EXPECT_EQ(ANeuralNetworksModel_create(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, AddOperand) {
|
|
ANeuralNetworksOperandType floatType{
|
|
.type = ANEURALNETWORKS_FLOAT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(nullptr, &floatType),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
ANeuralNetworksOperandType quant8TypeInvalidScale{
|
|
.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
|
|
.dimensionCount = 0,
|
|
.dimensions = nullptr,
|
|
// Scale has to be non-negative
|
|
.scale = -1.0f,
|
|
.zeroPoint = 0,
|
|
};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &quant8TypeInvalidScale),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ANeuralNetworksOperandType quant8TypeInvalidZeroPoint{
|
|
.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
|
|
.dimensionCount = 0,
|
|
.dimensions = nullptr,
|
|
.scale = 1.0f,
|
|
// zeroPoint has to be in [0, 255]
|
|
.zeroPoint = -1,
|
|
};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &quant8TypeInvalidZeroPoint),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
const uint32_t dim = 2;
|
|
ANeuralNetworksOperandType invalidScalarType{
|
|
.type = ANEURALNETWORKS_INT32,
|
|
// a scalar type must have 0 dimensions.
|
|
.dimensionCount = 1,
|
|
.dimensions = &dim,
|
|
};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &invalidScalarType),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &kInvalidTensorType1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &kInvalidTensorType2),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
modelFinish();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &floatType), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, SetOperandSymmPerChannelQuantParams) {
|
|
const int32_t operandIndex = addTensorOperand(ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL);
|
|
|
|
float scales[2] = {1.0, 2.0};
|
|
ANeuralNetworksSymmPerChannelQuantParams channelQuant = {
|
|
.channelDim = 0,
|
|
.scaleCount = 2,
|
|
.scales = scales,
|
|
};
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(nullptr, operandIndex,
|
|
&channelQuant),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, operandIndex, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, operandIndex + 1,
|
|
&channelQuant),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, operandIndex,
|
|
&channelQuant),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
#ifndef NNTEST_ONLY_PUBLIC_API
|
|
TEST_F(ValidationTestModelExtensions, AddOperand_UnknownPrefix) {
|
|
ANeuralNetworksOperandType type = {.type = -1};
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &type), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, SetOperandSymmPerChannelQuantParams_ExtensionOperand) {
|
|
const int32_t operandIndex =
|
|
addTensorOperand(getExtensionOperandType(kTestExtensionTensorType));
|
|
|
|
float scales[2] = {1.0, 2.0};
|
|
ANeuralNetworksSymmPerChannelQuantParams channelQuant = {
|
|
.channelDim = 0,
|
|
.scaleCount = 2,
|
|
.scales = scales,
|
|
};
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, operandIndex,
|
|
&channelQuant),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, SetOperandExtensionData) {
|
|
const int32_t operandIndex =
|
|
addTensorOperand(getExtensionOperandType(kTestExtensionTensorType));
|
|
const int32_t data = 42;
|
|
const size_t dataLength = sizeof(data);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksModel_setOperandExtensionData(nullptr, operandIndex, &data, dataLength),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksModel_setOperandExtensionData(mModel, operandIndex, nullptr, dataLength),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandExtensionData(mModel, operandIndex, &data, 0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandExtensionData(mModel, operandIndex + 1, &data,
|
|
dataLength),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandExtensionData(mModel, operandIndex, &data, dataLength),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, SetOperandExtensionData_Empty) {
|
|
const int32_t operandIndex =
|
|
addTensorOperand(getExtensionOperandType(kTestExtensionTensorType));
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandExtensionData(mModel, operandIndex, nullptr, 0),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, SetOperandExtensionData_NonExtensionOperand) {
|
|
const int32_t operandIndex = addTensorOperand();
|
|
const int32_t data = 42;
|
|
const size_t dataLength = sizeof(data);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandExtensionData(mModel, operandIndex, &data, dataLength),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, SetOperandValue_UnspecifiedDimension) {
|
|
const uint32_t dimensions[2] = {3, 0};
|
|
ANeuralNetworksOperandType type = {
|
|
.type = getExtensionOperandType(kTestExtensionTensorType),
|
|
.dimensionCount = 2,
|
|
.dimensions = dimensions,
|
|
};
|
|
const int32_t operandIndex = addOperand(type);
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, operandIndex, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, SetOperandValue_UnspecifiedRank) {
|
|
ANeuralNetworksOperandType type = {
|
|
.type = getExtensionOperandType(kTestExtensionTensorType),
|
|
.dimensionCount = 0,
|
|
.dimensions = nullptr,
|
|
};
|
|
const int32_t operandIndex = addOperand(type);
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, operandIndex, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModelExtensions, AddOperandDimensionProductOverflow) {
|
|
uint32_t dimensions[] = {5, 4, 4, 786433, 5, 3, 16777216, 4, 5};
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = getExtensionOperandType(kTestExtensionTensorType),
|
|
.dimensionCount = std::size(dimensions),
|
|
.dimensions = dimensions,
|
|
};
|
|
// This should fail, as the operand type's dimension product overflows uint32_t.
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
#endif
|
|
|
|
TEST_F(ValidationTestModel, SetOptionalOperand) {
|
|
ANeuralNetworksOperandType floatType{
|
|
.type = ANEURALNETWORKS_FLOAT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &floatType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 0, nullptr, 0),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, SetOperandValue) {
|
|
ANeuralNetworksOperandType floatType{
|
|
.type = ANEURALNETWORKS_FLOAT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &floatType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(nullptr, 0, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 0, nullptr, sizeof(buffer)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because buffer is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 0, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should succeed.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 0, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 1, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
modelFinish();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 0, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, SetOperandValueFromMemory) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType floatType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &floatType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd, 0,
|
|
&memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(nullptr, 0, memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, nullptr, 0, sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, -1, memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, 0, memorySize),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 1, memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because offset is larger than memorySize.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize + 1,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because requested size is larger than the memory.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize - 3,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
modelFinish();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
close(memoryFd);
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
TEST_F(ValidationTestModel, SetOperandValueFromAHardwareBuffer) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType quant8Type{.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
|
|
.dimensionCount = 1,
|
|
.dimensions = dimensions,
|
|
.scale = 1.0,
|
|
.zeroPoint = 0};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &quant8Type), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
AHardwareBuffer_Desc desc{
|
|
.width = 16,
|
|
.height = 16,
|
|
.layers = 1,
|
|
.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
|
|
.usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
|
|
};
|
|
|
|
AHardwareBuffer* buffer = nullptr;
|
|
ASSERT_EQ(AHardwareBuffer_allocate(&desc, &buffer), 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because non-BLOB AHardwareBuffer is not allowed.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, 0, sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
AHardwareBuffer_release(buffer);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, SetOperandValueFromAHardwareBufferBlob) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType floatType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &floatType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
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);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because offset is larger than memorySize.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize + 1,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because requested size is larger than the memory.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize - 3,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
AHardwareBuffer_release(buffer);
|
|
}
|
|
#endif // __ANDROID__
|
|
|
|
TEST_F(ValidationTestModel, SetOperandValueFromModel) {
|
|
uint32_t dimensions[] = {2};
|
|
ANeuralNetworksOperandType tensorType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(dimensions),
|
|
.dimensions = dimensions,
|
|
};
|
|
ANeuralNetworksOperandType scalarType = {.type = ANEURALNETWORKS_INT32};
|
|
ANeuralNetworksOperandType modelType = {.type = ANEURALNETWORKS_MODEL};
|
|
|
|
ANeuralNetworksModel* valueModel = nullptr;
|
|
ASSERT_EQ(ANeuralNetworksModel_create(&valueModel), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(valueModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(valueModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(valueModel, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(valueModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
uint32_t inList[3] = {0, 1, 2};
|
|
uint32_t outList[1] = {3};
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperation(valueModel, ANEURALNETWORKS_ADD, 3, inList, 1,
|
|
outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(valueModel, 3, inList, 1, outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &modelType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, as the value model is not finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromModel(mModel, 0, valueModel),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksModel_finish(valueModel);
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromModel(nullptr, 0, valueModel),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromModel(mModel, 0, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromModel(mModel, -1, valueModel),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromModel(mModel, 1, valueModel),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
modelFinish();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromModel(mModel, 0, valueModel),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
ANeuralNetworksModel_free(valueModel);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, AddOEMOperand) {
|
|
ANeuralNetworksOperandType OEMScalarType{
|
|
.type = ANEURALNETWORKS_OEM_SCALAR, .dimensionCount = 0, .dimensions = nullptr};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &OEMScalarType), ANEURALNETWORKS_NO_ERROR);
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 0, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const size_t kByteSizeOfOEMTensor = 4;
|
|
uint32_t dimensions[]{kByteSizeOfOEMTensor};
|
|
ANeuralNetworksOperandType OEMTensorType{
|
|
.type = ANEURALNETWORKS_TENSOR_OEM_BYTE, .dimensionCount = 1, .dimensions = dimensions};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &OEMTensorType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 1, buffer, kByteSizeOfOEMTensor),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
modelFinish();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &OEMTensorType), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, AddOperation) {
|
|
uint32_t input = 0;
|
|
uint32_t output = 0;
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperation(nullptr, ANEURALNETWORKS_AVERAGE_POOL_2D, 1, &input,
|
|
1, &output),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperation(mModel, ANEURALNETWORKS_AVERAGE_POOL_2D, 0, nullptr,
|
|
1, &output),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperation(mModel, ANEURALNETWORKS_AVERAGE_POOL_2D, 1, &input,
|
|
0, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
ANeuralNetworksOperationType invalidOp = -1;
|
|
EXPECT_EQ(addOperation(invalidOp, {input}, {output}), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
modelFinish();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(addOperation(ANEURALNETWORKS_AVERAGE_POOL_2D, {input}, {output}),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, IdentifyInputsAndOutputs) {
|
|
uint32_t input = 0;
|
|
uint32_t output = 0;
|
|
EXPECT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(nullptr, 1, &input, 1, &output),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 0, nullptr, 1, &output),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 1, &input, 0, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
createModel();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(identifyInputsAndOutputs({input}, {output}), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, RelaxComputationFloat32toFloat16) {
|
|
EXPECT_EQ(ANeuralNetworksModel_relaxComputationFloat32toFloat16(nullptr, true),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
createModel();
|
|
// This should fail, as the model is already finished.
|
|
EXPECT_EQ(ANeuralNetworksModel_relaxComputationFloat32toFloat16(mModel, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksModel_relaxComputationFloat32toFloat16(mModel, false),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, Finish) {
|
|
EXPECT_EQ(ANeuralNetworksModel_finish(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
createModel();
|
|
EXPECT_EQ(modelFinish(), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, EmptyModel) {
|
|
// An empty model is invalid
|
|
EXPECT_EQ(modelFinish(), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, CreateCompilation) {
|
|
ANeuralNetworksCompilation* compilation = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_create(nullptr, &compilation),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_create(mModel, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_create(mModel, &compilation), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, CreateCompilationForDevices) {
|
|
createModel();
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
if (numDevices > 0) {
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(0, &device), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksCompilation* compilation = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(nullptr, &device, 1, &compilation),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, &device, 1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// empty device list
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, &device, 0, &compilation),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// duplicate devices in the list.
|
|
ANeuralNetworksDevice* invalidDevices[2] = {device, device};
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, invalidDevices, 2,
|
|
&compilation),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// nullptr in the list.
|
|
invalidDevices[1] = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, invalidDevices, 2,
|
|
&compilation),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
ANeuralNetworksCompilation* compilation = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(nullptr, nullptr, 1, &compilation),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, nullptr, 1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, nullptr, 1, &compilation),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, GetSupportedOperationsForDevices) {
|
|
createModel();
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
bool supportedOps[20];
|
|
ASSERT_LE(mNumOperations, sizeof(supportedOps) / sizeof(supportedOps[0]));
|
|
if (numDevices > 0) {
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(0, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(nullptr, &device, 1,
|
|
supportedOps),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, &device, 1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// empty device list
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, &device, 0,
|
|
supportedOps),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// duplicate devices in the list.
|
|
ANeuralNetworksDevice* invalidDevices[2] = {device, device};
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, invalidDevices, 2,
|
|
supportedOps),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// nullptr in the list.
|
|
invalidDevices[1] = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, invalidDevices, 2,
|
|
supportedOps),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(nullptr, nullptr, 1,
|
|
supportedOps),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, nullptr, 1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, nullptr, 1, supportedOps),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, Cycle) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType tensorType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
ANeuralNetworksOperandType scalarType{
|
|
.type = ANEURALNETWORKS_INT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
|
|
// opnd0 = model input TENSOR_FLOAT32
|
|
// opnd1 = model input TENSOR_FLOAT32
|
|
// opnd2 = model input INT32
|
|
// opnd3 = ADD(opnd0, opnd4, opnd2)
|
|
// opnd4 = ADD(opnd1, opnd3, opnd2)
|
|
// opnd5 = ADD(opnd4, opnd0, opnd2) // model output
|
|
//
|
|
// +-----+
|
|
// | |
|
|
// v |
|
|
// 3 = ADD(0, 4, 2) |
|
|
// | |
|
|
// +----------+ |
|
|
// | |
|
|
// v |
|
|
// 4 = ADD(1, 3, 2) |
|
|
// | |
|
|
// +----------------+
|
|
// |
|
|
// |
|
|
// +-------+
|
|
// |
|
|
// v
|
|
// 5 = ADD(4, 0, 2)
|
|
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ADD, {0, 4, 2}, {3}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ADD, {1, 3, 2}, {4}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ADD, {4, 0, 2}, {5}), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2}, {5}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, AcyclicReadBeforeWrite) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType tensorType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
|
|
// opnd0 = TENSOR_FLOAT32 // model input
|
|
// opnd1 = LOGISTIC(opnd2) // model output
|
|
// opnd2 = LOGISTIC(opnd0)
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_LOGISTIC, {2}, {1}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_LOGISTIC, {0}, {2}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs({0}, {1}), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should succeed, because NN API doesn't require that operations be sorted.
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, MissingWrite) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType tensorType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
|
|
// opnd0 = TENSOR_FLOAT32 // model input
|
|
// opnd1 = TENSOR_FLOAT32 // never written
|
|
// opnd2 = LOGISTIC(opnd1) // model output
|
|
// opnd3 = LOGISTIC(opnd0) // model output
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_LOGISTIC, {1}, {2}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_LOGISTIC, {0}, {3}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs({0}, {2, 3}), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, UnwrittenOperand) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType tensorType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
|
|
// opnd0 = TENSOR_FLOAT32 // model input
|
|
// opnd1 = TENSOR_FLOAT32 // never written
|
|
// opnd2 = LOGISTIC(opnd0) // model output
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_LOGISTIC, {0}, {2}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs({0}, {2}), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, MultipleWrite) {
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType tensorType{
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32, .dimensionCount = 1, .dimensions = dimensions};
|
|
ANeuralNetworksOperandType scalarType{
|
|
.type = ANEURALNETWORKS_INT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
|
|
// opnd0 = TENSOR_FLOAT32 // model input
|
|
// opnd1 = INT32 // model input
|
|
// opnd2 = ADD(opnd0, opnd0, opnd1) // model output; do this twice
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &tensorType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
SCOPED_TRACE(i);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ADD, {0, 0, 1}, {2}), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1}, {2}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestIdentify, Ok) {
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2}, {3}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
TEST_F(ValidationTestIdentify, InputIsOutput) {
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2}, {3, 0}), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestIdentify, OutputIsInput) {
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2, 3}, {3}), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestIdentify, DuplicateInputs) {
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2, 0}, {3}), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestIdentify, DuplicateOutputs) {
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2}, {3, 3}), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, SetPreference)
|
|
TEST_F(ValidationTestCompilation, SetPreference) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPreference(nullptr, ANEURALNETWORKS_PREFER_LOW_POWER),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPreference(mCompilation, 40), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, SetCaching)
|
|
TEST_F(ValidationTestCompilation, SetCaching) {
|
|
std::vector<uint8_t> token(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, 0);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(nullptr, NN_TMP_DIR, token.data()),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, nullptr, token.data()),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, NN_TMP_DIR, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestCompilation, SetPriority) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPriority(nullptr, ANEURALNETWORKS_PRIORITY_DEFAULT),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// Test invalid values of priority.
|
|
constexpr int kInvalidPriorities[] = {0,
|
|
ANEURALNETWORKS_PRIORITY_LOW - 1,
|
|
ANEURALNETWORKS_PRIORITY_LOW + 1,
|
|
ANEURALNETWORKS_PRIORITY_MEDIUM - 1,
|
|
ANEURALNETWORKS_PRIORITY_MEDIUM + 1,
|
|
ANEURALNETWORKS_PRIORITY_HIGH - 1,
|
|
ANEURALNETWORKS_PRIORITY_HIGH + 1};
|
|
for (int invalidPriority : kInvalidPriorities) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPriority(mCompilation, invalidPriority),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, SetTimeout)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_2, SetTimeout)
|
|
TEST_F(ValidationTestCompilation, SetTimeout) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(nullptr, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
// Timeout can only be set on Compilations created from CompilationForDevices with one device
|
|
// specified.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestCompilation, GetPreferredMemoryAlignmentAndPadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
uint32_t result;
|
|
|
|
// The following calls should fail, because the compilation has not been finished.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput(mCompilation, 0,
|
|
&result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput(mCompilation, 0,
|
|
&result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput(mCompilation, 0,
|
|
&result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput(mCompilation, 0,
|
|
&result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// The following calls should fail because of unexpected nullptr.
|
|
EXPECT_EQ(
|
|
ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput(nullptr, 0, &result),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput(mCompilation, 0,
|
|
nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput(nullptr, 0, &result),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput(mCompilation, 0,
|
|
nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput(nullptr, 0,
|
|
&result),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput(mCompilation, 0,
|
|
nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput(nullptr, 0, &result),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput(mCompilation, 0,
|
|
nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// The following calls should fail, because the index is out of range.
|
|
const uint32_t invalidIndex = 1000;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput(
|
|
mCompilation, invalidIndex, &result),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput(
|
|
mCompilation, invalidIndex, &result),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput(
|
|
mCompilation, invalidIndex, &result),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput(
|
|
mCompilation, invalidIndex, &result),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, CreateExecution)
|
|
TEST_F(ValidationTestCompilation, CreateExecution) {
|
|
ANeuralNetworksExecution* execution = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(nullptr, &execution),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, Finish)
|
|
TEST_F(ValidationTestCompilation, Finish) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPreference(mCompilation,
|
|
ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksCompilation_setPriority(mCompilation, ANEURALNETWORKS_PRIORITY_DEFAULT),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
std::vector<uint8_t> token(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, 0);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, NN_TMP_DIR, token.data()),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, ExecutionSetTimeout)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_2, ExecutionSetTimeout)
|
|
TEST_F(ValidationTestCompilation, ExecutionSetTimeout) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(nullptr, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
// Timeout can only be set on Compilations created from CompilationForDevices with one device
|
|
// specified.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(execution, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, ExecutionTiming)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_2, ExecutionTiming)
|
|
TEST_F(ValidationTestCompilation, ExecutionTiming) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
// Cannot setMeasureTiming() with Compilation rather than CompilationForDevices.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, false),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, true), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, ExecutionTiming)
|
|
TEST_F(ValidationTestCompilation, ExecutionUsability) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
enum class ExecutionType : uint32_t { ASYNC, SYNC, BURST, FENCED };
|
|
for (auto executionType :
|
|
{ExecutionType::ASYNC, ExecutionType::SYNC, ExecutionType::BURST, ExecutionType::FENCED}) {
|
|
for (bool explicitlyDisableReusablility : {false, true}) {
|
|
SCOPED_TRACE(static_cast<uint32_t>(executionType));
|
|
SCOPED_TRACE(explicitlyDisableReusablility);
|
|
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
if (explicitlyDisableReusablility) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
ASSERT_EQ(ANeuralNetworksExecution_setReusable(execution, false),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
} else {
|
|
ANeuralNetworksExecution_free(execution);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Set inputs and outputs.
|
|
float in0[] = {0.0f, 0.0f}, in1[] = {1.0f, 1.0f}, out0[2];
|
|
int in2 = 0;
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &in1, sizeof(in1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &in2, sizeof(in2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(
|
|
ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0, sizeof(out0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const size_t memorySize = std::max(sizeof(in0), sizeof(out0));
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE,
|
|
memoryFd, 0, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
auto testTooLate = [this, execution, &in0, &out0, memory] {
|
|
// Try a bunch of things that are impermissible if the execution has started.
|
|
|
|
// Set loop timeout.
|
|
ASSERT_EQ(
|
|
ANeuralNetworksExecution_setLoopTimeout(execution, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// Enable/Disable input and output padding.
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
ASSERT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ASSERT_EQ(
|
|
ANeuralNetworksExecution_enableInputAndOutputPadding(execution, false),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Set inputs and outputs.
|
|
ASSERT_EQ(
|
|
ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0,
|
|
sizeof(out0)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInputFromMemory(execution, 0, nullptr, memory,
|
|
0, sizeof(in0)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr,
|
|
memory, 0, sizeof(out0)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// Set reusable.
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
ASSERT_EQ(ANeuralNetworksExecution_setReusable(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setReusable(execution, false),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Reuse for asynchronous execution.
|
|
{
|
|
ANeuralNetworksEvent* event;
|
|
ASSERT_EQ(ANeuralNetworksExecution_startCompute(execution, &event),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Reuse for synchronous execution.
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// Reuse for burst execution.
|
|
{
|
|
ANeuralNetworksBurst* burst;
|
|
ASSERT_EQ(ANeuralNetworksBurst_create(mCompilation, &burst),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_burstCompute(execution, burst),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksBurst_free(burst);
|
|
}
|
|
|
|
// Reuse for fenced execution.
|
|
{
|
|
ANeuralNetworksEvent* event;
|
|
ASSERT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(
|
|
execution, nullptr, 0, 0, &event),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
};
|
|
|
|
// Compute.
|
|
switch (executionType) {
|
|
case ExecutionType::ASYNC: {
|
|
ANeuralNetworksEvent* event;
|
|
ASSERT_EQ(ANeuralNetworksExecution_startCompute(execution, &event),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testTooLate();
|
|
ASSERT_EQ(ANeuralNetworksEvent_wait(event), ANEURALNETWORKS_NO_ERROR);
|
|
testTooLate();
|
|
ANeuralNetworksEvent_free(event);
|
|
break;
|
|
}
|
|
case ExecutionType::SYNC: {
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testTooLate();
|
|
break;
|
|
}
|
|
case ExecutionType::BURST: {
|
|
ANeuralNetworksBurst* burst;
|
|
ASSERT_EQ(ANeuralNetworksBurst_create(mCompilation, &burst),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_burstCompute(execution, burst),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testTooLate();
|
|
ANeuralNetworksBurst_free(burst);
|
|
break;
|
|
}
|
|
case ExecutionType::FENCED: {
|
|
ANeuralNetworksEvent* event;
|
|
ASSERT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(
|
|
execution, nullptr, 0, 0, &event),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testTooLate();
|
|
ASSERT_EQ(ANeuralNetworksEvent_wait(event), ANEURALNETWORKS_NO_ERROR);
|
|
testTooLate();
|
|
ANeuralNetworksEvent_free(event);
|
|
break;
|
|
}
|
|
default:
|
|
FAIL() << "Unreachable";
|
|
}
|
|
|
|
// close memory
|
|
ANeuralNetworksExecution_free(execution);
|
|
ANeuralNetworksMemory_free(memory);
|
|
close(memoryFd);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void testConcurrentExecution(bool reusable, ANeuralNetworksCompilation* compilation) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(compilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
enum class ExecutionType : uint32_t { ASYNC, SYNC, BURST, FENCED };
|
|
const auto compute = [compilation](ExecutionType executionType,
|
|
ANeuralNetworksExecution* execution) -> int {
|
|
switch (executionType) {
|
|
case ExecutionType::ASYNC: {
|
|
ANeuralNetworksEvent* event;
|
|
int result = ANeuralNetworksExecution_startCompute(execution, &event);
|
|
if (result == ANEURALNETWORKS_NO_ERROR) {
|
|
result = ANeuralNetworksEvent_wait(event);
|
|
}
|
|
ANeuralNetworksEvent_free(event);
|
|
return result;
|
|
}
|
|
case ExecutionType::SYNC: {
|
|
return ANeuralNetworksExecution_compute(execution);
|
|
}
|
|
case ExecutionType::BURST: {
|
|
ANeuralNetworksBurst* burst;
|
|
int result = ANeuralNetworksBurst_create(compilation, &burst);
|
|
if (result == ANEURALNETWORKS_NO_ERROR) {
|
|
result = ANeuralNetworksExecution_burstCompute(execution, burst);
|
|
}
|
|
ANeuralNetworksBurst_free(burst);
|
|
return result;
|
|
}
|
|
case ExecutionType::FENCED: {
|
|
ANeuralNetworksEvent* event;
|
|
int result = ANeuralNetworksExecution_startComputeWithDependencies(
|
|
execution, nullptr, 0, 0, &event);
|
|
if (result == ANEURALNETWORKS_NO_ERROR) {
|
|
result = ANeuralNetworksEvent_wait(event);
|
|
}
|
|
ANeuralNetworksEvent_free(event);
|
|
return result;
|
|
}
|
|
}
|
|
};
|
|
|
|
const std::vector<ExecutionType> kExecutionTypes = {
|
|
ExecutionType::ASYNC, ExecutionType::SYNC, ExecutionType::BURST, ExecutionType::FENCED};
|
|
for (auto executionType1 : kExecutionTypes) {
|
|
for (auto executionType2 : kExecutionTypes) {
|
|
SCOPED_TRACE(static_cast<uint32_t>(executionType1));
|
|
SCOPED_TRACE(static_cast<uint32_t>(executionType2));
|
|
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(compilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
float in0[] = {0.0f, 0.0f}, in1[] = {1.0f, 1.0f}, out0[2];
|
|
int in2 = 0;
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &in1, sizeof(in1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &in2, sizeof(in2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(
|
|
ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0, sizeof(out0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
ASSERT_EQ(ANeuralNetworksExecution_setReusable(execution, reusable),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
} else {
|
|
if (reusable) {
|
|
ANeuralNetworksExecution_free(execution);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Compute on the same execution concurrently.
|
|
auto first = std::async(std::launch::async, [compute, executionType1, execution] {
|
|
return compute(executionType1, execution);
|
|
});
|
|
auto second = std::async(std::launch::async, [compute, executionType2, execution] {
|
|
return compute(executionType2, execution);
|
|
});
|
|
const int result1 = first.get();
|
|
const int result2 = second.get();
|
|
|
|
// At least one result must be ANEURALNETWORKS_NO_ERROR. One may return
|
|
// ANEURALNETWORKS_BAD_STATE if the other is already executing.
|
|
EXPECT_TRUE(result1 == ANEURALNETWORKS_BAD_STATE ||
|
|
result1 == ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_TRUE(result2 == ANEURALNETWORKS_BAD_STATE ||
|
|
result2 == ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_TRUE(result1 == ANEURALNETWORKS_NO_ERROR || result2 == ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// If the execution is not reusable, one result must be ANEURALNETWORKS_BAD_STATE.
|
|
if (!reusable) {
|
|
EXPECT_TRUE(result1 == ANEURALNETWORKS_BAD_STATE ||
|
|
result2 == ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestBurst, BurstComputeConcurrent)
|
|
TEST_F(ValidationTestCompilation, ReusableExecutionConcurrent) {
|
|
testConcurrentExecution(/*reusable=*/true, mCompilation);
|
|
}
|
|
TEST_F(ValidationTestCompilation, NonReusableExecutionConcurrent) {
|
|
testConcurrentExecution(/*reusable=*/false, mCompilation);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetLoopTimeout) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_setLoopTimeout(nullptr, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, EnableInputAndOutputPadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(nullptr, true),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(nullptr, false),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, ExecutionSetReusable) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_setReusable(nullptr, true),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setReusable(nullptr, false),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetInput) {
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(nullptr, 0, nullptr, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, nullptr, sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, buffer, 20),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 999, nullptr, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, -1, nullptr, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// These should fail, because the tensor types are invalid.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, &kInvalidTensorType1, buffer,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, &kInvalidTensorType2, buffer,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Cannot do this twice.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetInputEnablePadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because length is less than the size of a float32.
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, buffer,
|
|
sizeof(float) - 1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetOutput) {
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(nullptr, 0, nullptr, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, nullptr, sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, buffer, 20),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 999, nullptr, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, as this operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, -1, nullptr, buffer, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// These should fail, because the tensor types are invalid.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, &kInvalidTensorType1, buffer,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, &kInvalidTensorType2, buffer,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Cannot do this twice.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetOutputEnablePadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because length is less than the size of a float32.
|
|
char buffer[20];
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, buffer,
|
|
sizeof(float) - 1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetInputFromMemory) {
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd, 0,
|
|
&memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(nullptr, 0, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, nullptr, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 999, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, -1, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
memorySize),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because offset is larger than memorySize.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory,
|
|
memorySize + 1, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because requested size is larger than the memory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory,
|
|
memorySize - 3, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// These should fail, because the tensor types are invalid.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, &kInvalidTensorType1,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, &kInvalidTensorType2,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Cannot do this twice.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0, 8),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
char buffer[memorySize];
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
close(memoryFd);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetInputFromMemoryEnablePadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd,
|
|
0, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because length is less than the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
sizeof(float) - 1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
close(memoryFd);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
TEST_F(ValidationTestExecution, SetInputFromAHardwareBufferBlob) {
|
|
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);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
memorySize),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because offset is larger than memorySize.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory,
|
|
memorySize + 1, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// This should fail, because requested size is larger than the memory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory,
|
|
memorySize - 3, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// These should fail, because the tensor types are invalid.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, &kInvalidTensorType1,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, &kInvalidTensorType2,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
AHardwareBuffer_release(buffer);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetInputFromAHardwareBufferBlobEnablePadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
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);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because length is less than the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
sizeof(float) - 1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
AHardwareBuffer_release(buffer);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
#endif // __ANDROID__
|
|
|
|
TEST_F(ValidationTestExecution, SetOutputFromMemory) {
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd, 0,
|
|
&memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(nullptr, 0, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, nullptr, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 999, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, -1, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0,
|
|
memorySize),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because offset is larger than memorySize.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory,
|
|
memorySize + 1, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because requested size is larger than the memory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory,
|
|
memorySize - 3, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// These should fail, because the tensor types are invalid.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, &kInvalidTensorType1,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, &kInvalidTensorType2,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Cannot do this twice.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0, 8),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
char buffer[memorySize];
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
ANeuralNetworksExecution_free(execution);
|
|
close(memoryFd);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetOutputFromMemoryEnablePadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd,
|
|
0, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because length is less than the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0,
|
|
sizeof(float) - 1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
ANeuralNetworksExecution_free(execution);
|
|
close(memoryFd);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
TEST_F(ValidationTestExecution, SetOutputFromAHardwareBufferBlob) {
|
|
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);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because memory is not the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
memorySize),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because offset is larger than memorySize.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory,
|
|
memorySize + 1, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// This should fail, because requested size is larger than the memory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory,
|
|
memorySize - 3, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// These should fail, because the tensor types are invalid.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, &kInvalidTensorType1,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, &kInvalidTensorType2,
|
|
memory, 0, sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
AHardwareBuffer_release(buffer);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, SetOutputFromAHardwareBufferBlobEnablePadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
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);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(mExecution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because length is less than the size of a float32.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
sizeof(float) - 1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
AHardwareBuffer_release(buffer);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
#endif // __ANDROID__
|
|
|
|
TEST_F(ValidationTestExecution, EnablePaddingAfterSetInputOutput) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
ANeuralNetworksExecution* execution;
|
|
char buffer[20];
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd,
|
|
0, &memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Enable padding after setInput.
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksExecution_free(execution);
|
|
|
|
// Enable padding after setInputFromMemory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(execution, 0, nullptr, memory, 0, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksExecution_free(execution);
|
|
|
|
// Enable padding after setOutput.
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, buffer, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksExecution_free(execution);
|
|
|
|
// Enable padding after setOutputFromMemory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0, 8),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_enableInputAndOutputPadding(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksExecution_free(execution);
|
|
|
|
// close memory
|
|
ANeuralNetworksMemory_free(memory);
|
|
close(memoryFd);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidationTestExecutionDeviceMemory, SetInputFromMemory) {
|
|
ANeuralNetworksMemoryDesc* desc;
|
|
ASSERT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// The following output roles are for init/deinit of the device memory.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, mInitCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, mDeinitCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &memory), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
// Uninitialized memory as input.
|
|
executeWithMemoryAsInput(mCompilation, memory, ANEURALNETWORKS_OP_FAILED);
|
|
|
|
// The memory is deinitialized between setInputFromMemory and compute.
|
|
{
|
|
// Initialize device memory.
|
|
executeWithMemoryAsOutput(mInitCompilation, memory, ANEURALNETWORKS_NO_ERROR);
|
|
|
|
float data = 0;
|
|
ANeuralNetworksExecution* execution = nullptr;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInputFromMemory(execution, 0, nullptr, memory, 0, 0),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &data, sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Deinitialize device memory.
|
|
executeWithMemoryAsOutput(mDeinitCompilation, memory, ANEURALNETWORKS_OP_FAILED);
|
|
|
|
// Uninitialized memory as input at compute time.
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), ANEURALNETWORKS_OP_FAILED);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
// Initialize device memory.
|
|
executeWithMemoryAsOutput(mInitCompilation, memory, ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Bad offset and length.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 1, 0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Bad usage -- not configured for this role.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory, 0, 0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Deinitialize device memory.
|
|
executeWithMemoryAsOutput(mDeinitCompilation, memory, ANEURALNETWORKS_OP_FAILED);
|
|
|
|
// Uninitialized memory as input.
|
|
executeWithMemoryAsInput(mCompilation, memory, ANEURALNETWORKS_OP_FAILED);
|
|
|
|
ANeuralNetworksMemory_free(memory);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecutionDeviceMemory, SetOutputFromMemory) {
|
|
ANeuralNetworksMemoryDesc* desc;
|
|
ASSERT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &memory), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
// Bad offset and length.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory, 1, 0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory, 0,
|
|
sizeof(float)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Bad usage -- not configured for this role.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0, 0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ANeuralNetworksMemory_free(memory);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecutionDeviceMemory, SetInputFromMemory_DynamicShape) {
|
|
uint32_t dimension = 1, badDimension = 2;
|
|
ANeuralNetworksOperandType badType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = 1,
|
|
.dimensions = &badDimension,
|
|
};
|
|
|
|
ANeuralNetworksMemoryDesc* desc;
|
|
ASSERT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, mCompilationDynamic, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(desc, 1, &dimension),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// The following output role is for init of the device memory.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, mInitCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &memory), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
// Initialize device memory.
|
|
executeWithMemoryAsOutput(mInitCompilation, memory, ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Incompatible dimensions between updated type and memory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecutionDynamic, 0, &badType, memory, 0,
|
|
0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ANeuralNetworksMemory_free(memory);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecutionDeviceMemory, SetOutputFromMemory_DynamicShape) {
|
|
uint32_t dimension = 1, badDimension = 2;
|
|
ANeuralNetworksOperandType badType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = 1,
|
|
.dimensions = &badDimension,
|
|
};
|
|
|
|
ANeuralNetworksMemoryDesc* desc;
|
|
ASSERT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, mCompilationDynamic, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(desc, 1, &dimension),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &memory), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
// Incompatible dimensions between updated type and memory.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecutionDynamic, 0, &badType, memory,
|
|
0, 0),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ANeuralNetworksMemory_free(memory);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, Compute) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_compute(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, StartCompute) {
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksEvent* event;
|
|
EXPECT_EQ(ANeuralNetworksExecution_startCompute(nullptr, &event),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_startCompute(execution, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// close memory
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, EventWait) {
|
|
EXPECT_EQ(ANeuralNetworksEvent_wait(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTest, EventCreateFromSyncFenceFd) {
|
|
ANeuralNetworksEvent* event;
|
|
EXPECT_EQ(ANeuralNetworksEvent_createFromSyncFenceFd(-1, &event), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksEvent_createFromSyncFenceFd(1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTest, EventGetSyncFenceFd) {
|
|
int syncFd = -100;
|
|
EXPECT_EQ(ANeuralNetworksEvent_getSyncFenceFd(nullptr, &syncFd),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(syncFd, -1);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, EventGetSyncFenceFdFromStartCompute) {
|
|
// Create a valid execution and event first.
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
float input0[] = {1.0f, 1.0f}, input1[] = {2.0f, 2.0f}, output0[2];
|
|
int32_t input2[] = {0};
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, input0, sizeof(input0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, input1, sizeof(input1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, input2, sizeof(input2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, output0, sizeof(output0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksEvent* event = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_startCompute(execution, &event), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// The event from startCompute is not backed by sync fence.
|
|
int syncFd = -100;
|
|
EXPECT_EQ(ANeuralNetworksEvent_getSyncFenceFd(event, &syncFd), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(syncFd, -1);
|
|
|
|
ANeuralNetworksEvent_free(event);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, FencedExecution) {
|
|
// Create a valid execution and event first.
|
|
ANeuralNetworksExecution* execution1;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution1), ANEURALNETWORKS_NO_ERROR);
|
|
float input0[] = {1.0f, 1.0f}, input1[] = {2.0f, 2.0f}, output0[2];
|
|
int32_t input2[] = {0};
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution1, 0, nullptr, input0, sizeof(input0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution1, 1, nullptr, input1, sizeof(input1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution1, 2, nullptr, input2, sizeof(input2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(execution1, 0, nullptr, output0, sizeof(output0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksEvent* event1 = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(execution1, nullptr, 0, 0,
|
|
&event1),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksEvent_getSyncFenceFd(event1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// The event from startComputeWithDependencie may or may not be backed by a sync fence depending
|
|
// on the driver implementation.
|
|
int syncFd = -100;
|
|
int getSyncFdResult = ANeuralNetworksEvent_getSyncFenceFd(event1, &syncFd);
|
|
if (getSyncFdResult == ANEURALNETWORKS_NO_ERROR) {
|
|
EXPECT_GE(syncFd, 0);
|
|
close(syncFd);
|
|
} else {
|
|
EXPECT_EQ(getSyncFdResult, ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(syncFd, -1);
|
|
}
|
|
|
|
// The subsequent execution will wait for the first execution to finish.
|
|
ANeuralNetworksExecution* execution2;
|
|
ANeuralNetworksEvent* event2 = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution2), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksExecution_startComputeWithDependencies(nullptr, &event1, 1, 0, &event2),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(execution2, nullptr, 1, 0,
|
|
&event2),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(execution2, &event1, 1, 0,
|
|
nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
ANeuralNetworksEvent* wait_for_list[] = {event1, nullptr};
|
|
EXPECT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(execution2, wait_for_list, 2, 0,
|
|
&event2),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
ANeuralNetworksEvent_free(event1);
|
|
ANeuralNetworksExecution_free(execution1);
|
|
ANeuralNetworksExecution_free(execution2);
|
|
}
|
|
|
|
TEST_F(ValidationTestExecution, GetOutputOperandRankAndDimensions) {
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
float input0[] = {1.0f, 1.0f}, input1[] = {2.0f, 2.0f}, output0[2];
|
|
int32_t input2[] = {0};
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, input0, sizeof(input0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, input1, sizeof(input1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, input2, sizeof(input2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, output0, sizeof(output0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
uint32_t rank, dims[4], expectedRank = 1, expectedDims = 2;
|
|
// This should fail, because the execution has not yet started to compute.
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandRank(execution, 0, &rank),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandDimensions(execution, 0, dims),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
ANeuralNetworksEvent* event;
|
|
EXPECT_EQ(ANeuralNetworksExecution_startCompute(execution, &event), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksEvent_wait(event), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because unexpected nullptr.
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandRank(nullptr, 0, &rank),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandDimensions(nullptr, 0, dims),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandRank(execution, 0, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandDimensions(execution, 0, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// This should fail, because the operand does not exist.
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandRank(execution, -1, &rank),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandRank(execution, 999, &rank),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandDimensions(execution, -1, dims),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandDimensions(execution, 999, dims),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandRank(execution, 0, &rank),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getOutputOperandDimensions(execution, 0, dims),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(rank, expectedRank);
|
|
EXPECT_EQ(dims[0], expectedDims);
|
|
|
|
// close memory
|
|
ANeuralNetworksEvent_free(event);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
// Regression test for b/146044137.
|
|
class ValidationTestDimensionProductOverflow : public ValidationTestExecution {
|
|
protected:
|
|
void createModel() override {
|
|
uint32_t dimensions[] = {5, 4, 4, 0, 5, 3, 0, 4, 5};
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(dimensions),
|
|
.dimensions = dimensions,
|
|
};
|
|
addOperand(operandType);
|
|
addOperand(operandType);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_ABS, {0}, {1}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs({0}, {1}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
};
|
|
|
|
TEST_F(ValidationTestDimensionProductOverflow, SetInputOrOutput) {
|
|
uint32_t dimensions[] = {5, 4, 4, 786433, 5, 3, 16777216, 4, 5};
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(dimensions),
|
|
.dimensions = dimensions,
|
|
};
|
|
uint8_t buffer[20];
|
|
// This should fail, as the new operand type's dimension product overflows
|
|
// uint32_t.
|
|
EXPECT_EQ(
|
|
ANeuralNetworksExecution_setInput(mExecution, 0, &operandType, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksExecution_setOutput(mExecution, 0, &operandType, buffer, sizeof(buffer)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestModel, AddOperandDimensionProductOverflow) {
|
|
uint32_t dimensions[] = {5, 4, 4, 786433, 5, 3, 16777216, 4, 5};
|
|
ANeuralNetworksOperandType operandType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(dimensions),
|
|
.dimensions = dimensions,
|
|
};
|
|
// This should fail, as the operand type's dimension product overflows uint32_t.
|
|
ASSERT_EQ(ANeuralNetworksModel_addOperand(mModel, &operandType), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
class ValidationTestDimensionProductOverflow2 : public ValidationTestExecution {
|
|
protected:
|
|
void createModel() override {
|
|
addTensorOperand(ANEURALNETWORKS_TENSOR_FLOAT32, {0, 1});
|
|
addTensorOperand(ANEURALNETWORKS_TENSOR_FLOAT32, {0, 1});
|
|
addTensorOperand(ANEURALNETWORKS_TENSOR_FLOAT32, {0});
|
|
addScalarOperand(ANEURALNETWORKS_INT32);
|
|
int32_t activation = 0;
|
|
ASSERT_EQ(ANeuralNetworksModel_setOperandValue(mModel, 3, &activation, sizeof(activation)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
addTensorOperand(ANEURALNETWORKS_TENSOR_FLOAT32, {0, 0});
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_FULLY_CONNECTED, {0, 1, 2, 3}, {4}),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs({0, 1, 2}, {4}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
};
|
|
|
|
TEST_F(ValidationTestDimensionProductOverflow2, DynamicOutputShapeOverflow) {
|
|
constexpr uint32_t kLargeDim = 1 << 16;
|
|
std::vector<float> inputData(kLargeDim), outputData(kLargeDim);
|
|
const uint32_t inputDims[] = {kLargeDim, 1};
|
|
const uint32_t biasDims[] = {kLargeDim};
|
|
const ANeuralNetworksOperandType inputType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(inputDims),
|
|
.dimensions = inputDims,
|
|
};
|
|
const ANeuralNetworksOperandType biasType = {
|
|
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(biasDims),
|
|
.dimensions = biasDims,
|
|
};
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, &inputType, inputData.data(),
|
|
inputData.size() * sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 1, &inputType, inputData.data(),
|
|
inputData.size() * sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 2, &biasType, inputData.data(),
|
|
inputData.size() * sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, outputData.data(),
|
|
outputData.size() * sizeof(float)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail, because the deduced output data size overflows uint32_t.
|
|
EXPECT_NE(ANeuralNetworksExecution_compute(mExecution), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
TEST_F(ValidationTestBurst, BurstComputeNull) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_burstCompute(mExecution, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_burstCompute(nullptr, mBurst),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestBurst, BurstComputeBadCompilation) {
|
|
ANeuralNetworksCompilation* compilation;
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mModel, &compilation), ANEURALNETWORKS_NO_ERROR);
|
|
// NOTE: ANeuralNetworksCompilation_finish not called
|
|
|
|
ANeuralNetworksBurst* burst;
|
|
EXPECT_EQ(ANeuralNetworksBurst_create(compilation, &burst), ANEURALNETWORKS_BAD_STATE);
|
|
|
|
// close memory
|
|
ANeuralNetworksBurst_free(burst);
|
|
ANeuralNetworksCompilation_free(compilation);
|
|
}
|
|
|
|
TEST_F(ValidationTestBurst, BurstComputeDifferentCompilations) {
|
|
ANeuralNetworksCompilation* secondCompilation;
|
|
ASSERT_EQ(ANeuralNetworksCompilation_create(mModel, &secondCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(secondCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(secondCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_burstCompute(execution, mBurst), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ANeuralNetworksExecution_free(execution);
|
|
ANeuralNetworksCompilation_free(secondCompilation);
|
|
}
|
|
|
|
TEST_F(ValidationTestBurst, BurstComputeConcurrent) {
|
|
ANeuralNetworksExecution* secondExecution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &secondExecution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// set inputs of first execution
|
|
float inputA0[] = {1.0f, 1.0f}, inputA1[] = {2.0f, 2.0f}, outputA0[2];
|
|
int32_t inputA2[] = {0};
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 0, nullptr, inputA0, sizeof(inputA0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 1, nullptr, inputA1, sizeof(inputA1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(mExecution, 2, nullptr, inputA2, sizeof(inputA2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksExecution_setOutput(mExecution, 0, nullptr, outputA0, sizeof(outputA0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// set inputs of second execution
|
|
float inputB0[] = {1.0f, 1.0f}, inputB1[] = {2.0f, 2.0f}, outputB0[2];
|
|
int32_t inputB2[] = {0};
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(secondExecution, 0, nullptr, inputB0,
|
|
sizeof(inputB0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(secondExecution, 1, nullptr, inputB1,
|
|
sizeof(inputB1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(secondExecution, 2, nullptr, inputB2,
|
|
sizeof(inputB2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutput(secondExecution, 0, nullptr, outputB0,
|
|
sizeof(outputB0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Execute on the same burst concurrently. At least one result must be
|
|
// ANEURALNETWORKS_NO_ERROR. One may return ANEURALNETWORKS_BAD_STATE if the
|
|
// other is already executing on the burst.
|
|
auto first = std::async(std::launch::async, [this] {
|
|
return ANeuralNetworksExecution_burstCompute(mExecution, mBurst);
|
|
});
|
|
auto second = std::async(std::launch::async, [this, secondExecution] {
|
|
return ANeuralNetworksExecution_burstCompute(secondExecution, mBurst);
|
|
});
|
|
|
|
const int result1 = first.get();
|
|
const int result2 = second.get();
|
|
EXPECT_TRUE(result1 == ANEURALNETWORKS_BAD_STATE || result1 == ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_TRUE(result2 == ANEURALNETWORKS_BAD_STATE || result2 == ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_TRUE(result1 == ANEURALNETWORKS_NO_ERROR || result2 == ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksExecution_free(secondExecution);
|
|
}
|
|
|
|
// The burst object maintains a local cache of memory objects. Because the burst
|
|
// is intended to live for multiple executions, and because memory might be
|
|
// created and freed for each execution, burst includes internal mechanisms to
|
|
// purge memory objects from its cache that have been freed by the NNAPI client.
|
|
// The following two test cases (FreeMemoryBeforeBurst and
|
|
// FreeBurstBeforeMemory) ensure that this internal cleanup is tested in both
|
|
// freeing orders.
|
|
//
|
|
// These two test cases explicitly create a new burst object and a new execution
|
|
// object so that the order of freeing can be specified. If these tests instead
|
|
// relied on the provided mExecution and mBurst, mBurst would always be freed
|
|
// before mExecution.
|
|
|
|
TEST_F(ValidationTestBurst, FreeMemoryBeforeBurst) {
|
|
ANeuralNetworksBurst* burst;
|
|
EXPECT_EQ(ANeuralNetworksBurst_create(mCompilation, &burst), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// prepare data for execution
|
|
float input0[] = {1.0f, 1.0f}, input1[] = {2.0f, 2.0f}, output0[2];
|
|
int32_t input2[] = {0};
|
|
|
|
const size_t memorySize = sizeof(output0);
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd, 0,
|
|
&memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// create and configure execution
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, input0, sizeof(input0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, input1, sizeof(input1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, input2, sizeof(input2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0,
|
|
sizeof(output0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// preform execution to cache memory into burst
|
|
EXPECT_EQ(ANeuralNetworksExecution_burstCompute(execution, burst), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution_free(execution);
|
|
|
|
// free memory before burst
|
|
ANeuralNetworksMemory_free(memory);
|
|
ANeuralNetworksBurst_free(burst);
|
|
|
|
// close memory
|
|
close(memoryFd);
|
|
}
|
|
|
|
TEST_F(ValidationTestBurst, FreeBurstBeforeMemory) {
|
|
ANeuralNetworksBurst* burst;
|
|
EXPECT_EQ(ANeuralNetworksBurst_create(mCompilation, &burst), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// prepare data for execution
|
|
float input0[] = {1.0f, 1.0f}, input1[] = {2.0f, 2.0f}, output0[2];
|
|
int32_t input2[] = {0};
|
|
const size_t memorySize = sizeof(output0);
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
ANeuralNetworksMemory* memory;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd, 0,
|
|
&memory),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// create and configure execution
|
|
ANeuralNetworksExecution* execution;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, input0, sizeof(input0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, input1, sizeof(input1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, input2, sizeof(input2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0,
|
|
sizeof(output0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// preform execution to cache memory into burst
|
|
EXPECT_EQ(ANeuralNetworksExecution_burstCompute(execution, burst), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution_free(execution);
|
|
|
|
// free burst before memory
|
|
ANeuralNetworksBurst_free(burst);
|
|
ANeuralNetworksMemory_free(memory);
|
|
|
|
// close memory
|
|
close(memoryFd);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, GetNumDevices) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, GetDevice) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksDevice* device = nullptr;
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
SCOPED_TRACE(i);
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_NE(device, nullptr);
|
|
}
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(0, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(numDevices, &device), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
static void deviceStringCheck(std::function<int(const ANeuralNetworksDevice*, const char**)> func) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const char* buffer;
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
SCOPED_TRACE(i);
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(func(device, &buffer), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(func(device, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
EXPECT_EQ(func(nullptr, &buffer), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(func(nullptr, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, DeviceGetName) {
|
|
deviceStringCheck(ANeuralNetworksDevice_getName);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, DeviceGetNameUnique) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
std::set<std::string> deviceNames;
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
ANeuralNetworksDevice* device = nullptr;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
const char* buffer = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksDevice_getName(device, &buffer), ANEURALNETWORKS_NO_ERROR);
|
|
std::string name(buffer);
|
|
EXPECT_EQ(deviceNames.count(name), (uint32_t)0);
|
|
deviceNames.insert(name);
|
|
}
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, DeviceGetVersion) {
|
|
deviceStringCheck(ANeuralNetworksDevice_getVersion);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, DeviceGetFeatureLevel) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
int64_t featureLevel;
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
SCOPED_TRACE(i);
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getFeatureLevel(device, &featureLevel),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getFeatureLevel(device, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksDevice_getFeatureLevel(nullptr, &featureLevel),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getFeatureLevel(nullptr, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, DeviceGetType) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
int32_t validTypes[] = {ANEURALNETWORKS_DEVICE_UNKNOWN, ANEURALNETWORKS_DEVICE_OTHER,
|
|
ANEURALNETWORKS_DEVICE_CPU, ANEURALNETWORKS_DEVICE_GPU,
|
|
ANEURALNETWORKS_DEVICE_ACCELERATOR};
|
|
int32_t deviceType;
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
SCOPED_TRACE(i);
|
|
// Initialize the deviceType to be an invalid type.
|
|
deviceType = -1;
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getType(device, &deviceType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_TRUE(std::find(std::begin(validTypes), std::end(validTypes), deviceType) !=
|
|
std::end(validTypes));
|
|
EXPECT_EQ(ANeuralNetworksDevice_getType(device, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksDevice_getType(nullptr, &deviceType), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getType(nullptr, nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST(ValidationTestIntrospection, DeviceWait) {
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
SCOPED_TRACE(i);
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksDevice_wait(device), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksDevice_wait(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
class ValidationTestCompilationForDevices_1 : public ValidationTestModel {
|
|
protected:
|
|
virtual void SetUp() override {
|
|
ValidationTestModel::SetUp();
|
|
createModel();
|
|
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
if (numDevices > 0) {
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(0, &mDevice), ANEURALNETWORKS_NO_ERROR);
|
|
bool supported = false;
|
|
ASSERT_EQ(mNumOperations, static_cast<uint32_t>(1));
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, &mDevice, 1,
|
|
&supported),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
if (supported) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, &mDevice, 1,
|
|
&mCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
ANeuralNetworksCompilation_free(mCompilation);
|
|
ValidationTestModel::TearDown();
|
|
}
|
|
|
|
ANeuralNetworksDevice* mDevice = nullptr;
|
|
ANeuralNetworksCompilation* mCompilation = nullptr;
|
|
};
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, SetPreference)
|
|
TEST_F(ValidationTestCompilationForDevices_1, SetPreference) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPreference(nullptr, ANEURALNETWORKS_PREFER_LOW_POWER),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPreference(mCompilation, 40), ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, SetCaching)
|
|
TEST_F(ValidationTestCompilationForDevices_1, SetCaching) {
|
|
std::vector<uint8_t> token(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, 0);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(nullptr, NN_TMP_DIR, token.data()),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, nullptr, token.data()),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, NN_TMP_DIR, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, CreateExecution)
|
|
TEST_F(ValidationTestCompilationForDevices_1, CreateExecution) {
|
|
ANeuralNetworksExecution* execution = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(nullptr, &execution),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, Finish)
|
|
TEST_F(ValidationTestCompilationForDevices_1, Finish) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setPreference(mCompilation,
|
|
ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(
|
|
ANeuralNetworksCompilation_setPriority(mCompilation, ANEURALNETWORKS_PRIORITY_DEFAULT),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
std::vector<uint8_t> token(ANEURALNETWORKS_BYTE_SIZE_OF_CACHE_TOKEN, 0);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, NN_TMP_DIR, token.data()),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, SetTimeout)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_2, SetTimeout)
|
|
TEST_F(ValidationTestCompilationForDevices_1, SetTimeout) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Attempt to finish
|
|
const int n = ANeuralNetworksCompilation_finish(mCompilation);
|
|
EXPECT_TRUE(n == ANEURALNETWORKS_NO_ERROR || n == ANEURALNETWORKS_MISSED_DEADLINE_TRANSIENT ||
|
|
n == ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT);
|
|
}
|
|
|
|
TEST_F(ValidationTestCompilationForDevices_1, SetTimeoutMaximum) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
|
|
constexpr uint64_t duration = std::numeric_limits<uint64_t>::max();
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, duration),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
|
|
class ValidationTestCompilationForDevices_2 : public ValidationTestModel {
|
|
protected:
|
|
virtual void SetUp() override {
|
|
ValidationTestModel::SetUp();
|
|
createModel();
|
|
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
if (numDevices > 1) {
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(0, &mDevices[0]), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(1, &mDevices[1]), ANEURALNETWORKS_NO_ERROR);
|
|
bool supported = false;
|
|
ASSERT_EQ(mNumOperations, static_cast<uint32_t>(1));
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, mDevices, 2,
|
|
&supported),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
if (supported) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, mDevices, 2,
|
|
&mCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
ANeuralNetworksCompilation_free(mCompilation);
|
|
ValidationTestModel::TearDown();
|
|
}
|
|
|
|
ANeuralNetworksDevice* mDevices[2] = {nullptr, nullptr};
|
|
ANeuralNetworksCompilation* mCompilation = nullptr;
|
|
};
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, SetTimeout)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, SetTimeout)
|
|
TEST_F(ValidationTestCompilationForDevices_2, SetTimeout) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(nullptr, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
// Timeouts can only be set on Compilations created from CompilationForDevices with one device
|
|
// specified.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, ExecutionSetTimeout)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, ExecutionSetTimeout)
|
|
TEST_F(ValidationTestCompilationForDevices_2, ExecutionSetTimeout) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(nullptr, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
// Timeouts can only be set on Compilations created from CompilationForDevices with one device
|
|
// specified.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(execution, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, ExecutionTiming)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_1, ExecutionTiming)
|
|
TEST_F(ValidationTestCompilationForDevices_2, ExecutionTiming) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
// Cannot setMeasureTiming() if there are two or more devices.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, false),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, true), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// close memory
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
class ValidationTestInvalidCompilation : public ValidationTestModel {
|
|
protected:
|
|
virtual void SetUp() override {
|
|
ValidationTestModel::SetUp();
|
|
|
|
// Create a model with an OEM operation
|
|
uint32_t dimensions[]{1};
|
|
ANeuralNetworksOperandType OEMTensorType{.type = ANEURALNETWORKS_TENSOR_OEM_BYTE,
|
|
.dimensionCount = 1,
|
|
.dimensions = dimensions};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &OEMTensorType),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &OEMTensorType),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(addOperation(ANEURALNETWORKS_OEM_OPERATION, {0}, {1}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(identifyInputsAndOutputs({0}, {1}), ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(modelFinish(), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Find a device that cannot handle OEM operation and create compilation on that
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
bool supported = false;
|
|
EXPECT_EQ(ANeuralNetworksModel_getSupportedOperationsForDevices(mModel, &device, 1,
|
|
&supported),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
if (!supported) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_createForDevices(mModel, &device, 1,
|
|
&mInvalidCompilation),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
break;
|
|
}
|
|
}
|
|
if (mInvalidCompilation) {
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mInvalidCompilation),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
ANeuralNetworksCompilation_free(mInvalidCompilation);
|
|
ValidationTestModel::TearDown();
|
|
}
|
|
|
|
ANeuralNetworksCompilation* mInvalidCompilation = nullptr;
|
|
};
|
|
|
|
TEST_F(ValidationTestInvalidCompilation, GetPreferredMemoryAlignmentAndPadding) {
|
|
if (__builtin_available(android __NNAPI_FL5_MIN_ANDROID_API__, *)) {
|
|
if (!mInvalidCompilation) {
|
|
return;
|
|
}
|
|
uint32_t result;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForInput(
|
|
mInvalidCompilation, 0, &result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForInput(mInvalidCompilation,
|
|
0, &result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryAlignmentForOutput(
|
|
mInvalidCompilation, 0, &result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_getPreferredMemoryPaddingForOutput(mInvalidCompilation,
|
|
0, &result),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
} else {
|
|
GTEST_SKIP();
|
|
}
|
|
}
|
|
|
|
TEST_F(ValidationTestInvalidCompilation, CreateExecution) {
|
|
if (!mInvalidCompilation) {
|
|
return;
|
|
}
|
|
ANeuralNetworksExecution* execution = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_create(mInvalidCompilation, &execution),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
TEST_F(ValidationTestInvalidCompilation, MemoryDescAddRole) {
|
|
if (!mInvalidCompilation) {
|
|
return;
|
|
}
|
|
ANeuralNetworksMemoryDesc* desc = nullptr;
|
|
ASSERT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, mInvalidCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, mInvalidCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, ExecutionTiming)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_2, ExecutionTiming)
|
|
// Also see TEST_F(ValidationTestCompilation, ExecutionUsability)
|
|
TEST_F(ValidationTestCompilationForDevices_1, ExecutionTiming) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
enum class ExecutionType : uint32_t { ASYNC, SYNC, BURST, FENCED };
|
|
for (auto executionType :
|
|
{ExecutionType::ASYNC, ExecutionType::SYNC, ExecutionType::BURST, ExecutionType::FENCED}) {
|
|
SCOPED_TRACE(static_cast<uint32_t>(executionType));
|
|
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(nullptr, false),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(nullptr, true),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, false),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, true),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
float in0[] = {0.0f, 0.0f}, in1[] = {1.0f, 1.0f}, out0[2];
|
|
int in2 = 0;
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &in1, sizeof(in1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &in2, sizeof(in2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0, sizeof(out0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Cannot getDuration until the execution has finished.
|
|
uint64_t duration;
|
|
EXPECT_EQ(ANeuralNetworksExecution_getDuration(
|
|
execution, ANEURALNETWORKS_DURATION_ON_HARDWARE, &duration),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksExecution_getDuration(
|
|
execution, ANEURALNETWORKS_DURATION_IN_DRIVER, &duration),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
auto testSetTimeoutTooLate = [execution] {
|
|
// Cannot setTimeout if the execution has started.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(execution, kShortWaitInNanoseconds),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
};
|
|
|
|
auto testMeasureTooLate = [execution] {
|
|
// Cannot setMeasureTiming if the execution has started.
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, false),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setMeasureTiming(execution, true),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
};
|
|
|
|
// Compute.
|
|
switch (executionType) {
|
|
case ExecutionType::ASYNC: {
|
|
ANeuralNetworksEvent* event;
|
|
ASSERT_EQ(ANeuralNetworksExecution_startCompute(execution, &event),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testMeasureTooLate();
|
|
ASSERT_EQ(ANeuralNetworksEvent_wait(event), ANEURALNETWORKS_NO_ERROR);
|
|
testSetTimeoutTooLate();
|
|
testMeasureTooLate();
|
|
ANeuralNetworksEvent_free(event);
|
|
break;
|
|
}
|
|
case ExecutionType::SYNC: {
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), ANEURALNETWORKS_NO_ERROR);
|
|
testSetTimeoutTooLate();
|
|
testMeasureTooLate();
|
|
break;
|
|
}
|
|
case ExecutionType::BURST: {
|
|
ANeuralNetworksBurst* burst;
|
|
ASSERT_EQ(ANeuralNetworksBurst_create(mCompilation, &burst),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_burstCompute(execution, burst),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testSetTimeoutTooLate();
|
|
testMeasureTooLate();
|
|
ANeuralNetworksBurst_free(burst);
|
|
break;
|
|
}
|
|
case ExecutionType::FENCED: {
|
|
ANeuralNetworksEvent* event = nullptr;
|
|
ASSERT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(execution, nullptr,
|
|
0, 0, &event),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
testMeasureTooLate();
|
|
ASSERT_EQ(ANeuralNetworksEvent_wait(event), ANEURALNETWORKS_NO_ERROR);
|
|
testSetTimeoutTooLate();
|
|
testMeasureTooLate();
|
|
ANeuralNetworksEvent_free(event);
|
|
break;
|
|
}
|
|
default:
|
|
FAIL() << "Unreachable";
|
|
}
|
|
|
|
auto testDuration = [](ANeuralNetworksExecution* e, int32_t durationCode,
|
|
bool nullDuration) {
|
|
SCOPED_TRACE(e);
|
|
SCOPED_TRACE(durationCode);
|
|
SCOPED_TRACE(nullDuration);
|
|
|
|
// Strictly speaking, a duration COULD have this value, but it is
|
|
// exceedingly unlikely. We'll use it as an initial value that we expect
|
|
// to be modified by getDuration().
|
|
const uint64_t kBogusDuration = UINT64_MAX - 1;
|
|
|
|
uint64_t duration = kBogusDuration;
|
|
uint64_t* durationPtr = nullDuration ? nullptr : &duration;
|
|
|
|
int expectedResultCode = ANEURALNETWORKS_NO_ERROR;
|
|
if (e == nullptr | durationPtr == nullptr) {
|
|
expectedResultCode = ANEURALNETWORKS_UNEXPECTED_NULL;
|
|
} else if (durationCode < 0 ||
|
|
durationCode > ANEURALNETWORKS_FENCED_DURATION_IN_DRIVER) {
|
|
expectedResultCode = ANEURALNETWORKS_BAD_DATA;
|
|
}
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_getDuration(e, durationCode, durationPtr),
|
|
expectedResultCode);
|
|
if (expectedResultCode == ANEURALNETWORKS_NO_ERROR) {
|
|
EXPECT_NE(duration, kBogusDuration);
|
|
}
|
|
};
|
|
|
|
std::vector<ANeuralNetworksExecution*> executions = {nullptr, execution};
|
|
std::vector<int32_t> durationCodes = {-1,
|
|
ANEURALNETWORKS_DURATION_ON_HARDWARE,
|
|
ANEURALNETWORKS_DURATION_IN_DRIVER,
|
|
ANEURALNETWORKS_FENCED_DURATION_ON_HARDWARE,
|
|
ANEURALNETWORKS_FENCED_DURATION_IN_DRIVER,
|
|
ANEURALNETWORKS_FENCED_DURATION_IN_DRIVER + 1};
|
|
std::vector<bool> nullDurations = {false, true};
|
|
for (auto e : executions) {
|
|
for (auto d : durationCodes) {
|
|
for (auto n : nullDurations) {
|
|
testDuration(e, d, n);
|
|
}
|
|
}
|
|
}
|
|
|
|
// close memory
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
}
|
|
|
|
enum class TimeoutDurationType { SHORT, MAXIMUM };
|
|
uint64_t createTimeoutDuration(TimeoutDurationType type) {
|
|
switch (type) {
|
|
case TimeoutDurationType::SHORT:
|
|
return kShortWaitInNanoseconds;
|
|
case TimeoutDurationType::MAXIMUM:
|
|
return std::numeric_limits<uint64_t>::max();
|
|
}
|
|
LOG(FATAL) << "Invalid TimeoutDurationType: " << static_cast<int>(type);
|
|
return 0;
|
|
}
|
|
|
|
void runExecutionSetTimeoutTest(ANeuralNetworksCompilation* compilation,
|
|
TimeoutDurationType timeoutDurationType) {
|
|
if (!compilation) {
|
|
return;
|
|
}
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(compilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
enum class ExecutionType : uint32_t { ASYNC, SYNC, BURST, FENCED };
|
|
for (auto executionType :
|
|
{ExecutionType::ASYNC, ExecutionType::SYNC, ExecutionType::BURST, ExecutionType::FENCED}) {
|
|
SCOPED_TRACE(static_cast<uint32_t>(executionType));
|
|
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(compilation, &execution),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
const auto scoped = android::base::make_scope_guard(
|
|
[execution] { ANeuralNetworksExecution_free(execution); });
|
|
|
|
float in0[] = {0.0f, 0.0f}, in1[] = {1.0f, 1.0f}, out0[2];
|
|
int in2 = 0;
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &in1, sizeof(in1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &in2, sizeof(in2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0, sizeof(out0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const uint64_t timeoutDuration = createTimeoutDuration(timeoutDurationType);
|
|
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(execution, timeoutDuration),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const auto checkResult = [timeoutDurationType](int n) {
|
|
switch (timeoutDurationType) {
|
|
case TimeoutDurationType::SHORT:
|
|
EXPECT_TRUE(n == ANEURALNETWORKS_NO_ERROR ||
|
|
n == ANEURALNETWORKS_MISSED_DEADLINE_TRANSIENT ||
|
|
n == ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT);
|
|
return;
|
|
case TimeoutDurationType::MAXIMUM:
|
|
EXPECT_EQ(n, ANEURALNETWORKS_NO_ERROR);
|
|
return;
|
|
}
|
|
LOG(FATAL) << "Invalid TimeoutDurationType: " << static_cast<int>(timeoutDurationType);
|
|
};
|
|
|
|
// Compute.
|
|
switch (executionType) {
|
|
case ExecutionType::ASYNC: {
|
|
ANeuralNetworksEvent* event = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_startCompute(execution, &event),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
checkResult(ANeuralNetworksEvent_wait(event));
|
|
ANeuralNetworksEvent_free(event);
|
|
break;
|
|
}
|
|
case ExecutionType::SYNC: {
|
|
checkResult(ANeuralNetworksExecution_compute(execution));
|
|
break;
|
|
}
|
|
case ExecutionType::BURST: {
|
|
ANeuralNetworksBurst* burst;
|
|
ASSERT_EQ(ANeuralNetworksBurst_create(compilation, &burst),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
checkResult(ANeuralNetworksExecution_burstCompute(execution, burst));
|
|
ANeuralNetworksBurst_free(burst);
|
|
break;
|
|
}
|
|
case ExecutionType::FENCED: {
|
|
ANeuralNetworksEvent* event = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksExecution_startComputeWithDependencies(execution, nullptr,
|
|
0, 0, &event),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
checkResult(ANeuralNetworksEvent_wait(event));
|
|
ANeuralNetworksEvent_free(event);
|
|
break;
|
|
}
|
|
default:
|
|
FAIL() << "Unreachable";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilation, ExecutionSetTimeout)
|
|
// Also see TEST_F(ValidationTestCompilationForDevices_2, ExecutionSetTimeout)
|
|
TEST_F(ValidationTestCompilationForDevices_1, ExecutionSetTimeout) {
|
|
runExecutionSetTimeoutTest(mCompilation, TimeoutDurationType::SHORT);
|
|
}
|
|
|
|
TEST_F(ValidationTestCompilationForDevices_1, ExecutionSetTimeoutMaximum) {
|
|
runExecutionSetTimeoutTest(mCompilation, TimeoutDurationType::MAXIMUM);
|
|
}
|
|
|
|
TEST_F(ValidationTest, CreateMemoryDesc) {
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, AddInputRole) {
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(nullptr, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, nullptr, 0, 1.0f),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// Unfinished compilation.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Index out of range.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 999, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Invalid frequency.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 10.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 0.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, -1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Specify the same operand twice.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Attempting to modify a finished descriptor.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(mDesc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, AddOutputRole) {
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(nullptr, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, nullptr, 0, 1.0f),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// Unfinished compilation.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Index out of range.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 999, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Invalid frequency.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, 10.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, 0.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, -1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Specify the same operand twice.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Attempting to modify a finished descriptor.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(mDesc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Creates and compiles a single-operation ADD model with the given operand type.
|
|
// The caller is responsible to free the returned model and compilation.
|
|
static std::pair<ANeuralNetworksModel*, ANeuralNetworksCompilation*>
|
|
createAndCompileAddModelWithType(const ANeuralNetworksOperandType& type) {
|
|
// OperandType for activation scalar.
|
|
const ANeuralNetworksOperandType actType = {
|
|
.type = ANEURALNETWORKS_INT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
|
|
ANeuralNetworksModel* model;
|
|
EXPECT_EQ(ANeuralNetworksModel_create(&model), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &type), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &type), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &actType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &type), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const uint32_t inList[] = {0, 1, 2};
|
|
const uint32_t outList[] = {3};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_ADD, 3, inList, 1, outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(model, 3, inList, 1, outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_finish(model), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksCompilation* compilation;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_create(model, &compilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(compilation), ANEURALNETWORKS_NO_ERROR);
|
|
return {model, compilation};
|
|
}
|
|
|
|
static void testIncompatibleOperands(const ANeuralNetworksCompilation* compilation,
|
|
const ANeuralNetworksOperandType& badType) {
|
|
const auto [badModel, badCompilation] = createAndCompileAddModelWithType(badType);
|
|
{
|
|
ANeuralNetworksMemoryDesc* desc = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, compilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, badCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, badCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
}
|
|
{
|
|
ANeuralNetworksMemoryDesc* desc = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, compilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, badCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addOutputRole(desc, badCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
}
|
|
ANeuralNetworksCompilation_free(badCompilation);
|
|
ANeuralNetworksModel_free(badModel);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, OperandMetadata) {
|
|
const uint32_t dimensions[] = {2};
|
|
const uint32_t rank = std::size(dimensions);
|
|
const ANeuralNetworksOperandType floatBase = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = rank,
|
|
.dimensions = dimensions,
|
|
.scale = 0.0f,
|
|
.zeroPoint = 0};
|
|
const ANeuralNetworksOperandType quantBase = {.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
|
|
.dimensionCount = rank,
|
|
.dimensions = dimensions,
|
|
.scale = 1.0f,
|
|
.zeroPoint = 0};
|
|
const auto [floatModel, floatCompilation] = createAndCompileAddModelWithType(floatBase);
|
|
const auto [quantModel, quantCompilation] = createAndCompileAddModelWithType(quantBase);
|
|
|
|
// Different data type.
|
|
{
|
|
SCOPED_TRACE("Data type");
|
|
ANeuralNetworksOperandType wrongType = floatBase;
|
|
wrongType.type = ANEURALNETWORKS_TENSOR_FLOAT16;
|
|
testIncompatibleOperands(floatCompilation, wrongType);
|
|
}
|
|
|
|
// Different scale.
|
|
{
|
|
SCOPED_TRACE("Scale");
|
|
ANeuralNetworksOperandType wrongScale = quantBase;
|
|
wrongScale.scale = 0.5f;
|
|
testIncompatibleOperands(quantCompilation, wrongScale);
|
|
}
|
|
|
|
// Different zero point.
|
|
{
|
|
SCOPED_TRACE("Zero point");
|
|
ANeuralNetworksOperandType wrongZeroPoint = quantBase;
|
|
wrongZeroPoint.zeroPoint = 128;
|
|
testIncompatibleOperands(quantCompilation, wrongZeroPoint);
|
|
}
|
|
|
|
// Different rank.
|
|
{
|
|
SCOPED_TRACE("Rank");
|
|
const uint32_t badDimensions[] = {2, 1};
|
|
const uint32_t badRank = std::size(badDimensions);
|
|
ANeuralNetworksOperandType wrongRank = quantBase;
|
|
wrongRank.dimensionCount = badRank;
|
|
wrongRank.dimensions = badDimensions;
|
|
testIncompatibleOperands(quantCompilation, wrongRank);
|
|
}
|
|
|
|
// Different dimensions.
|
|
{
|
|
SCOPED_TRACE("Dimensions");
|
|
const uint32_t badDimensions[] = {1};
|
|
ANeuralNetworksOperandType wrongDims = quantBase;
|
|
wrongDims.dimensions = badDimensions;
|
|
testIncompatibleOperands(quantCompilation, wrongDims);
|
|
}
|
|
|
|
ANeuralNetworksCompilation_free(floatCompilation);
|
|
ANeuralNetworksCompilation_free(quantCompilation);
|
|
ANeuralNetworksModel_free(floatModel);
|
|
ANeuralNetworksModel_free(quantModel);
|
|
}
|
|
|
|
// Creates and compiles a single-operation CONV_2D model with channel quant data type of the given
|
|
// scales. The caller is responsible to free the returned model and compilation.
|
|
static std::pair<ANeuralNetworksModel*, ANeuralNetworksCompilation*>
|
|
createAndCompileChannelQuantConvModel(const std::vector<float>& scales) {
|
|
const uint32_t numChannels = scales.size();
|
|
|
|
// OperandType for input and output.
|
|
const uint32_t inoutDimensions[] = {1, 16, 16, numChannels};
|
|
const ANeuralNetworksOperandType inoutType = {
|
|
.type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM,
|
|
.dimensionCount = std::size(inoutDimensions),
|
|
.dimensions = inoutDimensions,
|
|
.scale = 1.0f,
|
|
.zeroPoint = 0,
|
|
};
|
|
|
|
// OperandType for filter.
|
|
const uint32_t filterDimensions[] = {numChannels, 3, 3, numChannels};
|
|
const ANeuralNetworksOperandType filterType = {
|
|
.type = ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL,
|
|
.dimensionCount = std::size(filterDimensions),
|
|
.dimensions = filterDimensions,
|
|
.scale = 0.0f,
|
|
.zeroPoint = 0,
|
|
};
|
|
|
|
// OperandType for bias.
|
|
const uint32_t biasDimensions[] = {numChannels};
|
|
const ANeuralNetworksOperandType biasType = {
|
|
.type = ANEURALNETWORKS_TENSOR_INT32,
|
|
.dimensionCount = std::size(biasDimensions),
|
|
.dimensions = biasDimensions,
|
|
.scale = 0.0f,
|
|
.zeroPoint = 0,
|
|
};
|
|
|
|
// OperandType for scalars: implicit padding code, strides, activation.
|
|
const ANeuralNetworksOperandType scalarType = {
|
|
.type = ANEURALNETWORKS_INT32, .dimensionCount = 0, .dimensions = nullptr};
|
|
|
|
ANeuralNetworksModel* model;
|
|
EXPECT_EQ(ANeuralNetworksModel_create(&model), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &inoutType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &filterType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &biasType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &scalarType), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperand(model, &inoutType), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// Set channel quant parameters for the filter tensor.
|
|
const ANeuralNetworksSymmPerChannelQuantParams channelQuant = {
|
|
.channelDim = 0,
|
|
.scaleCount = numChannels,
|
|
.scales = scales.data(),
|
|
};
|
|
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(model, 1, &channelQuant),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
const uint32_t inList[] = {0, 1, 2, 3, 4, 5, 6};
|
|
const uint32_t outList[] = {7};
|
|
EXPECT_EQ(ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_CONV_2D, std::size(inList),
|
|
inList, std::size(outList), outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(model, std::size(inList), inList,
|
|
std::size(outList), outList),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksModel_finish(model), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
ANeuralNetworksCompilation* compilation;
|
|
EXPECT_EQ(ANeuralNetworksCompilation_create(model, &compilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(compilation), ANEURALNETWORKS_NO_ERROR);
|
|
return {model, compilation};
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, ExtraParams) {
|
|
// Create two compilations with conflict channel quant scales.
|
|
const auto [model1, compilation1] = createAndCompileChannelQuantConvModel({1.0f, 1.0f});
|
|
const auto [model2, compilation2] = createAndCompileChannelQuantConvModel({0.5f, 0.5f});
|
|
|
|
ANeuralNetworksMemoryDesc* desc = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, compilation1, 1, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, compilation2, 1, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
ANeuralNetworksCompilation_free(compilation1);
|
|
ANeuralNetworksCompilation_free(compilation2);
|
|
ANeuralNetworksModel_free(model1);
|
|
ANeuralNetworksModel_free(model2);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, SetDimensions) {
|
|
const uint32_t dimensions[] = {2};
|
|
const uint32_t badDimensions[] = {3};
|
|
const uint32_t rank = std::size(dimensions);
|
|
const uint32_t badRankDimensions[] = {2, 1};
|
|
const uint32_t badRank = std::size(badRankDimensions);
|
|
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(nullptr, rank, dimensions),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, rank, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// Incompatible dimensions.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, rank, dimensions),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, rank, badDimensions),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, badRank, badRankDimensions),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Attempting to modify a finished descriptor.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(mDesc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, rank, dimensions),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, SetScalarDimensionsBeforeAddRole) {
|
|
const uint32_t badDimensions[] = {2};
|
|
const uint32_t badRank = std::size(badDimensions);
|
|
|
|
// Set non-zero rank.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, badRank, badDimensions),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail because input2 is a scalar.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 2, 1.0f),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, SetScalarDimensionsAfterAddRole) {
|
|
const uint32_t badDimensions[] = {2};
|
|
const uint32_t badRank = std::size(badDimensions);
|
|
|
|
// Input2 is a scalar.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 2, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// This should fail because the rank is not zero.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, 0, nullptr), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_setDimensions(mDesc, badRank, badDimensions),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, Finish) {
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(nullptr), ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// No usage is specified.
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(mDesc), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Finish an already finished descriptor.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(mDesc, mCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(mDesc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(mDesc), ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
TEST_F(ValidationTestMemoryDesc, CreateMemory) {
|
|
ANeuralNetworksMemory* memory = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(nullptr, &memory),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(mDesc, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// Unfinished descriptor.
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(mDesc, &memory), ANEURALNETWORKS_BAD_STATE);
|
|
|
|
ANeuralNetworksMemory_free(memory);
|
|
}
|
|
|
|
TEST(ValidationTestMemory, CreateFromFd) {
|
|
const size_t memorySize = 20;
|
|
#ifdef __ANDROID__
|
|
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
|
|
#else // __ANDROID__
|
|
TemporaryFile tmpFile;
|
|
int memoryFd = tmpFile.release();
|
|
CHECK_EQ(ftruncate(memoryFd, memorySize), 0);
|
|
#endif // __ANDROID__
|
|
ASSERT_GT(memoryFd, 0);
|
|
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromFd(memorySize, PROT_READ | PROT_WRITE, memoryFd, 0,
|
|
nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
close(memoryFd);
|
|
}
|
|
|
|
#ifdef __ANDROID__
|
|
TEST(ValidationTestMemory, CreateFromAHardwareBuffer) {
|
|
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);
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(buffer, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
AHardwareBuffer_release(buffer);
|
|
|
|
ANeuralNetworksMemory* memory = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromAHardwareBuffer(nullptr, &memory),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
}
|
|
#endif // __ANDROID__
|
|
|
|
TEST_F(ValidationTestMemoryDesc, MemoryCopying) {
|
|
uint32_t goodSize = sizeof(float) * 2, badSize1 = sizeof(float), badSize2 = sizeof(float) * 4;
|
|
ANeuralNetworksMemory* goodAshmem = createAshmem(goodSize);
|
|
ANeuralNetworksMemory* badAshmem1 = createAshmem(badSize1);
|
|
ANeuralNetworksMemory* badAshmem2 = createAshmem(badSize2);
|
|
|
|
const uint32_t goodDimensions[] = {1, 2};
|
|
const uint32_t badDimensions1[] = {2};
|
|
const uint32_t badDimensions2[] = {2, 1};
|
|
const ANeuralNetworksOperandType goodType = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(goodDimensions),
|
|
.dimensions = goodDimensions,
|
|
.scale = 0.0f,
|
|
.zeroPoint = 0};
|
|
const ANeuralNetworksOperandType badType1 = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(badDimensions1),
|
|
.dimensions = badDimensions1,
|
|
.scale = 0.0f,
|
|
.zeroPoint = 0};
|
|
const ANeuralNetworksOperandType badType2 = {.type = ANEURALNETWORKS_TENSOR_FLOAT32,
|
|
.dimensionCount = std::size(badDimensions2),
|
|
.dimensions = badDimensions2,
|
|
.scale = 0.0f,
|
|
.zeroPoint = 0};
|
|
const auto [goodModel, goodCompilation] = createAndCompileAddModelWithType(goodType);
|
|
const auto [badModel1, badCompilation1] = createAndCompileAddModelWithType(badType1);
|
|
const auto [badModel2, badCompilation2] = createAndCompileAddModelWithType(badType2);
|
|
|
|
ANeuralNetworksMemoryDesc* desc = nullptr;
|
|
ANeuralNetworksMemory *goodDeviceMemory1 = nullptr, *goodDeviceMemory2 = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, goodCompilation, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &goodDeviceMemory1),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &goodDeviceMemory2),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
ANeuralNetworksMemory* badDeviceMemory1 = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, badCompilation1, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &badDeviceMemory1),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
ANeuralNetworksMemory* badDeviceMemory2 = nullptr;
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_addInputRole(desc, badCompilation2, 0, 1.0f),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemoryDesc_finish(desc), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(desc, &badDeviceMemory2),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksMemoryDesc_free(desc);
|
|
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(nullptr, goodDeviceMemory1),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory1, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// Ashmem -> Ashmem
|
|
// Bad memory size.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, badAshmem1), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, badAshmem2), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem1, goodAshmem), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem2, goodAshmem), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Ashmem -> Device Memory
|
|
// Bad memory size.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem1, goodDeviceMemory1), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem2, goodDeviceMemory1), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Device Memory -> Ashmem
|
|
// Uninitialized source device memory.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory1, goodAshmem), ANEURALNETWORKS_BAD_DATA);
|
|
// Bad memory size.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, goodDeviceMemory1), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory1, badAshmem1), ANEURALNETWORKS_BAD_DATA);
|
|
// Uninitialized source device memory (after a failed copy).
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem1, goodDeviceMemory1), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory1, goodAshmem), ANEURALNETWORKS_BAD_DATA);
|
|
// Bad memory size.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, goodDeviceMemory1), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory1, badAshmem2), ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// Device Memory -> Device Memory
|
|
// Uninitialized source device memory.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory2, goodDeviceMemory1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// Incompatible rank.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, badDeviceMemory1), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badDeviceMemory1, goodDeviceMemory1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// Incompatible dimensions.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, badDeviceMemory2), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badDeviceMemory2, goodDeviceMemory1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// Deinitialized source device memory.
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, goodDeviceMemory2), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem1, goodDeviceMemory2), ANEURALNETWORKS_BAD_DATA);
|
|
EXPECT_EQ(ANeuralNetworksMemory_copy(goodDeviceMemory2, goodDeviceMemory1),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
ANeuralNetworksMemory_free(goodDeviceMemory1);
|
|
ANeuralNetworksMemory_free(goodDeviceMemory2);
|
|
ANeuralNetworksMemory_free(badDeviceMemory1);
|
|
ANeuralNetworksMemory_free(badDeviceMemory2);
|
|
ANeuralNetworksCompilation_free(goodCompilation);
|
|
ANeuralNetworksCompilation_free(badCompilation1);
|
|
ANeuralNetworksCompilation_free(badCompilation2);
|
|
ANeuralNetworksModel_free(goodModel);
|
|
ANeuralNetworksModel_free(badModel1);
|
|
ANeuralNetworksModel_free(badModel2);
|
|
}
|
|
|
|
#ifndef NNTEST_ONLY_PUBLIC_API
|
|
TEST(ValidationTestDevice, GetExtensionSupport) {
|
|
bool result;
|
|
EXPECT_EQ(ANeuralNetworksDevice_getExtensionSupport(nullptr, kTestExtensionName, &result),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
uint32_t numDevices = 0;
|
|
EXPECT_EQ(ANeuralNetworks_getDeviceCount(&numDevices), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
for (uint32_t i = 0; i < numDevices; i++) {
|
|
SCOPED_TRACE(i);
|
|
ANeuralNetworksDevice* device;
|
|
EXPECT_EQ(ANeuralNetworks_getDevice(i, &device), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getExtensionSupport(device, kTestExtensionName, nullptr),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getExtensionSupport(device, nullptr, &result),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksDevice_getExtensionSupport(device, kTestExtensionName, &result),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
}
|
|
}
|
|
|
|
constexpr const char* kTestAttributeExtensionName = "com.android.test_attribute_extension";
|
|
const uint16_t kAttributeCode = 0;
|
|
const uint16_t kAttributeCode2 = 2;
|
|
const uint8_t kAttributeValue = 0;
|
|
|
|
class ValidationTestCompilationExtension : public ValidationTestCompilation {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestCompilation::SetUp();
|
|
EXPECT_TRUE(::android::nn::TypeManager::get()->forTest_registerExtension({
|
|
.name = kTestAttributeExtensionName,
|
|
.operandTypes = {},
|
|
}));
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
::android::nn::TypeManager::get()->forTest_reset();
|
|
ValidationTestCompilation::TearDown();
|
|
}
|
|
};
|
|
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_1, AddExtensionAttribute)
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_2, AddExtensionAttribute)
|
|
TEST_F(ValidationTestCompilationExtension, AddExtensionAttribute) {
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(nullptr, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, nullptr, kAttributeCode, &kAttributeValue, sizeof(uint8_t)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode, nullptr,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
// ExtensionAttribute can only be added to Compilations created from CompilationForDevices with
|
|
// one device specified.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_1, ExecutionAddExtensionAttribute)
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_2, ExecutionAddExtensionAttribute)
|
|
TEST_F(ValidationTestCompilationExtension, ExecutionAddExtensionAttribute) {
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(nullptr, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, nullptr, kAttributeCode,
|
|
&kAttributeValue, sizeof(uint8_t)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode, nullptr,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_UNEXPECTED_NULL);
|
|
// ExtensionAttribute can only be added to Executions created from CompilationForDevices with
|
|
// one device specified.
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
class ValidationTestCompilationExtensionForDevices_1
|
|
: public ValidationTestCompilationForDevices_1 {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestCompilationForDevices_1::SetUp();
|
|
EXPECT_TRUE(::android::nn::TypeManager::get()->forTest_registerExtension({
|
|
.name = kTestAttributeExtensionName,
|
|
.operandTypes = {},
|
|
}));
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
::android::nn::TypeManager::get()->forTest_reset();
|
|
ValidationTestCompilationForDevices_1::TearDown();
|
|
}
|
|
};
|
|
|
|
// Also see TEST_F(ValidationTestCompilationExtension, AddExtensionAttribute)
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_2, AddExtensionAttribute)
|
|
TEST_F(ValidationTestCompilationExtensionForDevices_1, AddExtensionAttribute) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
// Adding another attribute.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode2, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
// Adding the same attribute twice is illegal.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
// Attempt to finish
|
|
const int n = ANeuralNetworksCompilation_finish(mCompilation);
|
|
EXPECT_TRUE(n == ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationExtension, ExecutionAddExtensionAttribute)
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_2, ExecutionAddExtensionAttribute)
|
|
TEST_F(ValidationTestCompilationExtensionForDevices_1, ExecutionAddExtensionAttribute) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
// Adding another attribute.
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode2, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
// Adding the same attribute twice is illegal.
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
|
|
// start the execution
|
|
float in0[] = {0.0f, 0.0f}, in1[] = {1.0f, 1.0f}, out0[2];
|
|
int in2 = 0;
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &in1, sizeof(in1)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &in2, sizeof(in2)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0, sizeof(out0)),
|
|
ANEURALNETWORKS_NO_ERROR);
|
|
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_STATE);
|
|
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
|
|
class ValidationTestCompilationExtensionForDevices_2
|
|
: public ValidationTestCompilationForDevices_2 {
|
|
protected:
|
|
virtual void SetUp() {
|
|
ValidationTestCompilationForDevices_2::SetUp();
|
|
EXPECT_TRUE(::android::nn::TypeManager::get()->forTest_registerExtension({
|
|
.name = kTestAttributeExtensionName,
|
|
.operandTypes = {},
|
|
}));
|
|
}
|
|
|
|
virtual void TearDown() {
|
|
::android::nn::TypeManager::get()->forTest_reset();
|
|
ValidationTestCompilationForDevices_2::TearDown();
|
|
}
|
|
};
|
|
|
|
// Also see TEST_F(ValidationTestCompilationExtension, AddExtensionAttribute)
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_1, AddExtensionAttribute)
|
|
TEST_F(ValidationTestCompilationExtensionForDevices_2, AddExtensionAttribute) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
// ExtensionAttribute can only be added to Compilations created from CompilationForDevices with
|
|
// one device specified.
|
|
EXPECT_EQ(ANeuralNetworksCompilation_addExtensionAttribute(
|
|
mCompilation, kTestAttributeExtensionName, kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
}
|
|
|
|
// Also see TEST_F(ValidationTestCompilationExtension, ExecutionAddExtensionAttribute)
|
|
// Also see TEST_F(ValidationTestCompilationExtensionForDevices_1, ExecutionAddExtensionAttribute)
|
|
TEST_F(ValidationTestCompilationExtensionForDevices_2, ExecutionAddExtensionAttribute) {
|
|
if (!mCompilation) {
|
|
return;
|
|
}
|
|
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
|
|
ANeuralNetworksExecution* execution;
|
|
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
|
|
|
|
// ExtensionAttribute can only be added to Executions created from CompilationForDevices with
|
|
// one device specified.
|
|
EXPECT_EQ(ANeuralNetworksExecution_addExtensionAttribute(execution, kTestAttributeExtensionName,
|
|
kAttributeCode, &kAttributeValue,
|
|
sizeof(uint8_t)),
|
|
ANEURALNETWORKS_BAD_DATA);
|
|
ANeuralNetworksExecution_free(execution);
|
|
}
|
|
#endif // NNTEST_ONLY_PUBLIC_API
|
|
|
|
} // namespace
|