blob: 446f0eba8e49d76987e15bfb58b8e682dba0f457 [file]
/*
* 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>
#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 "NeuralNetworks.h"
#include "NeuralNetworksOEM.h"
#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) {
uint32_t dimensions[] = {2};
ANeuralNetworksOperandType operandType = {
.type = type,
.dimensionCount = sizeof(dimensions) / sizeof(dimensions[0]),
.dimensions = dimensions,
};
return addOperand(operandType);
}
void createModel() {
addTensorOperand();
addTensorOperand();
addScalarOperand();
addTensorOperand();
uint32_t inList[3]{0, 1, 2};
uint32_t outList[1]{3};
ASSERT_EQ(ANeuralNetworksModel_addOperation(mModel, ANEURALNETWORKS_ADD, 3, inList, 1,
outList),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 3, inList, 1, outList),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksModel_finish(mModel), ANEURALNETWORKS_NO_ERROR);
mNumOperations = 1;
}
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);
uint32_t inList[3]{0, 1, 2};
uint32_t outList[1]{3};
ASSERT_EQ(ANeuralNetworksModel_addOperation(mModel, ANEURALNETWORKS_ADD, 3, inList, 1,
outList),
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) {
int fd = ASharedMemory_create("nnMemory", size);
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);
ANeuralNetworksModel_setOperandValue(model, 1, &constData, sizeof(float));
ANeuralNetworksModel_setOperandValue(model, 2, &actData, sizeof(uint32_t));
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);
ANeuralNetworksModel_finish(mModel);
// 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);
}
#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, since 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);
ANeuralNetworksModel_finish(mModel);
// 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;
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
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, since the operand does not exist.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, -1, memory, 0, sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since 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, since offset is larger than memorySize.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize + 1,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since requested size is larger than the memory.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize - 3,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
ANeuralNetworksModel_finish(mModel);
// This should fail, as the model is already finished.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, 0, sizeof(float)),
ANEURALNETWORKS_BAD_STATE);
// close memory
close(memoryFd);
}
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, since non-BLOB AHardwareBuffer is not allowed.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, 0, sizeof(uint8_t)),
ANEURALNETWORKS_BAD_DATA);
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, since offset is larger than memorySize.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize + 1,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since requested size is larger than the memory.
EXPECT_EQ(ANeuralNetworksModel_setOperandValueFromMemory(mModel, 0, memory, memorySize - 3,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
AHardwareBuffer_release(buffer);
}
TEST_F(ValidationTestModel, SetOperandValueFromModel) {
uint32_t dimensions[] = {2};
ANeuralNetworksOperandType tensorType = {
.type = ANEURALNETWORKS_TENSOR_FLOAT32,
.dimensionCount = 2,
.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, since 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);
ANeuralNetworksModel_finish(mModel);
// 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);
ANeuralNetworksModel_finish(mModel);
// 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(ANeuralNetworksModel_addOperation(mModel, invalidOp, 1, &input, 1, &output),
ANEURALNETWORKS_BAD_DATA);
ANeuralNetworksModel_finish(mModel);
// This should fail, as the model is already finished.
EXPECT_EQ(ANeuralNetworksModel_addOperation(mModel, ANEURALNETWORKS_AVERAGE_POOL_2D, 1, &input,
1, &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(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 1, &input, 1, &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(ANeuralNetworksModel_finish(mModel), ANEURALNETWORKS_BAD_STATE);
}
TEST_F(ValidationTestModel, EmptyModel) {
// An empty model is invalid
EXPECT_EQ(ANeuralNetworksModel_finish(mModel), 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(ValidationTestIdentify, Ok) {
uint32_t inList[3]{0, 1, 2};
uint32_t outList[1]{3};
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 3, inList, 1, outList),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksModel_finish(mModel), ANEURALNETWORKS_NO_ERROR);
}
TEST_F(ValidationTestIdentify, InputIsOutput) {
uint32_t inList[3]{0, 1, 2};
uint32_t outList[2]{3, 0};
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 3, inList, 2, outList),
ANEURALNETWORKS_BAD_DATA);
}
TEST_F(ValidationTestIdentify, OutputIsInput) {
uint32_t inList[4]{0, 1, 2, 3};
uint32_t outList[1]{3};
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 4, inList, 1, outList),
ANEURALNETWORKS_BAD_DATA);
}
TEST_F(ValidationTestIdentify, DuplicateInputs) {
uint32_t inList[4]{0, 1, 2, 0};
uint32_t outList[1]{3};
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 4, inList, 1, outList),
ANEURALNETWORKS_BAD_DATA);
}
TEST_F(ValidationTestIdentify, DuplicateOutputs) {
uint32_t inList[3]{0, 1, 2};
uint32_t outList[2]{3, 3};
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 3, inList, 2, outList),
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, "/data/local/tmp", token.data()),
ANEURALNETWORKS_UNEXPECTED_NULL);
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, nullptr, token.data()),
ANEURALNETWORKS_UNEXPECTED_NULL);
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, "/data/local/tmp", nullptr),
ANEURALNETWORKS_UNEXPECTED_NULL);
}
TEST_F(ValidationTestCompilation, SetPriority) {
EXPECT_EQ(ANeuralNetworksCompilation_setPriority(nullptr, ANEURALNETWORKS_PRIORITY_DEFAULT),
ANEURALNETWORKS_UNEXPECTED_NULL);
}
// 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);
}
// 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, "/data/local/tmp", 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);
}
// 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}) {
SCOPED_TRACE(static_cast<uint32_t>(executionType));
ANeuralNetworksExecution* execution;
ASSERT_EQ(ANeuralNetworksExecution_create(mCompilation, &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);
const size_t memorySize = std::max(sizeof(in0), sizeof(out0));
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
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 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);
// 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";
}
}
}
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, since 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, since 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);
}
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, since 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, since 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);
}
TEST_F(ValidationTestExecution, SetInputFromMemory) {
const size_t memorySize = 20;
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
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, since the operand does not exist.
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 999, nullptr, memory, 0,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since the operand does not exist.
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, -1, nullptr, memory, 0,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since memory is not the size of a float32.
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
memorySize),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since offset is larger than memorySize.
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory,
memorySize + 1, sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since 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, since 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
close(memoryFd);
}
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, since memory is not the size of a float32.
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory, 0,
memorySize),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since offset is larger than memorySize.
EXPECT_EQ(ANeuralNetworksExecution_setInputFromMemory(mExecution, 0, nullptr, memory,
memorySize + 1, sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since 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, since 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);
AHardwareBuffer_release(buffer);
}
TEST_F(ValidationTestExecution, SetOutputFromMemory) {
ANeuralNetworksExecution* execution;
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
const size_t memorySize = 20;
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
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, since the operand does not exist.
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 999, nullptr, memory, 0,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since the operand does not exist.
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, -1, nullptr, memory, 0,
sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since memory is not the size of a float32.
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory, 0,
memorySize),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since offset is larger than memorySize.
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(execution, 0, nullptr, memory,
memorySize + 1, sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since 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, since 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);
// close memory
close(memoryFd);
}
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, since memory is not the size of a float32.
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory, 0,
memorySize),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since offset is larger than memorySize.
EXPECT_EQ(ANeuralNetworksExecution_setOutputFromMemory(mExecution, 0, nullptr, memory,
memorySize + 1, sizeof(float)),
ANEURALNETWORKS_BAD_DATA);
// This should fail, since 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, since 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);
AHardwareBuffer_release(buffer);
}
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.
// TODO(xusongw): Additionally validate the case when the state of the memory is changed
// between setInputFromMemory and compute.
executeWithMemoryAsInput(mCompilation, memory, ANEURALNETWORKS_OP_FAILED);
// 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);
}
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 sync_fd = -1;
EXPECT_EQ(ANeuralNetworksEvent_getSyncFenceFd(nullptr, &sync_fd),
ANEURALNETWORKS_UNEXPECTED_NULL);
}
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 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, since 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, since 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, since 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);
}
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);
}
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);
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
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);
int memoryFd = ASharedMemory_create("nnMemory", memorySize);
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, DeviceSupportsTimeouts) {
EXPECT_FALSE(ANeuralNetworksDevice_supportsCompilationTimeout(nullptr));
EXPECT_FALSE(ANeuralNetworksDevice_supportsExecutionTimeout(nullptr));
}
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, "/data/local/tmp", token.data()),
ANEURALNETWORKS_UNEXPECTED_NULL);
if (!mCompilation) {
return;
}
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, nullptr, token.data()),
ANEURALNETWORKS_UNEXPECTED_NULL);
EXPECT_EQ(ANeuralNetworksCompilation_setCaching(mCompilation, "/data/local/tmp", 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, "/data/local/tmp", 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;
}
// Find whether device being tested supports compilation timeout
const bool compilationTimeout = ANeuralNetworksDevice_supportsCompilationTimeout(mDevice);
// Attempt to set the timeout, expect failure if not supported
const int compilationTimeoutExpectedResult =
compilationTimeout ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_BAD_DATA;
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, kShortWaitInNanoseconds),
compilationTimeoutExpectedResult);
// Attempt to finish
const int n = ANeuralNetworksCompilation_finish(mCompilation);
if (compilationTimeout && n != ANEURALNETWORKS_NO_ERROR) {
EXPECT_TRUE(n == ANEURALNETWORKS_MISSED_DEADLINE_TRANSIENT ||
n == ANEURALNETWORKS_MISSED_DEADLINE_PERSISTENT);
} else {
EXPECT_EQ(n, ANEURALNETWORKS_NO_ERROR);
}
}
TEST_F(ValidationTestCompilationForDevices_1, SetTimeoutOverflow) {
if (!mCompilation) {
return;
}
// Find whether device being tested supports compilation timeout
const bool compilationTimeout = ANeuralNetworksDevice_supportsCompilationTimeout(mDevice);
// Test that timeout overflow is caught only when the device supports
// compilation timeout
if (compilationTimeout) {
constexpr uint64_t duration = std::numeric_limits<uint64_t>::max();
EXPECT_EQ(ANeuralNetworksCompilation_setTimeout(mCompilation, duration),
ANEURALNETWORKS_NO_ERROR);
EXPECT_NE(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_OP_FAILED);
}
}
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);
}
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);
uint32_t inList[1]{0};
uint32_t outList[1]{1};
ASSERT_EQ(ANeuralNetworksModel_addOperation(mModel, ANEURALNETWORKS_OEM_OPERATION, 1,
inList, 1, outList),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 1, inList, 1, outList),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksModel_finish(mModel), 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, 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);
const bool executionTimeout = ANeuralNetworksDevice_supportsExecutionTimeout(mDevice);
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, executionTimeout] {
const int setTimeoutExpectedResult =
executionTimeout ? ANEURALNETWORKS_BAD_STATE : ANEURALNETWORKS_BAD_DATA;
// Cannot setTimeout if the execution has started.
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(execution, kShortWaitInNanoseconds),
setTimeoutExpectedResult);
};
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);
}
}
}
}
}
enum class TimeoutDurationType { SHORT, OVERFLOW };
uint64_t createTimeoutDuration(TimeoutDurationType type) {
switch (type) {
case TimeoutDurationType::SHORT:
return kShortWaitInNanoseconds;
case TimeoutDurationType::OVERFLOW:
return std::numeric_limits<uint64_t>::max();
}
LOG(FATAL) << "Invalid TimeoutDurationType: " << static_cast<int>(type);
return 0;
}
void runExecutionSetTimeoutTest(const ANeuralNetworksDevice* device,
ANeuralNetworksCompilation* compilation,
TimeoutDurationType timeoutDurationType) {
if (!compilation) {
return;
}
ASSERT_EQ(ANeuralNetworksCompilation_finish(compilation), ANEURALNETWORKS_NO_ERROR);
const bool executionTimeout = ANeuralNetworksDevice_supportsExecutionTimeout(device);
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);
const int executionTimeoutExpectedResult =
executionTimeout ? ANEURALNETWORKS_NO_ERROR : ANEURALNETWORKS_BAD_DATA;
EXPECT_EQ(ANeuralNetworksExecution_setTimeout(execution, timeoutDuration),
executionTimeoutExpectedResult);
if (!executionTimeout) {
// Skip execution if execution with timeout is not supported.
continue;
}
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::OVERFLOW:
EXPECT_EQ(n, ANEURALNETWORKS_OP_FAILED);
return;
}
LOG(FATAL) << "Invalid TimeoutDurationType: " << static_cast<int>(timeoutDurationType);
};
// Compute.
switch (executionType) {
case ExecutionType::ASYNC: {
ANeuralNetworksEvent* event = nullptr;
ASSERT_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;
ASSERT_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(mDevice, mCompilation, TimeoutDurationType::SHORT);
}
TEST_F(ValidationTestCompilationForDevices_1, ExecutionSetTimeoutOverflow) {
runExecutionSetTimeoutTest(mDevice, mCompilation, TimeoutDurationType::OVERFLOW);
}
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);
}
// TODO(xusongw): Test different extra parameters.
ANeuralNetworksCompilation_free(floatCompilation);
ANeuralNetworksCompilation_free(quantCompilation);
ANeuralNetworksModel_free(floatModel);
ANeuralNetworksModel_free(quantModel);
}
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_F(ValidationTestMemoryDesc, MemoryCopying) {
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
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);
ANeuralNetworksMemory *deviceMemory1 = nullptr, *deviceMemory2 = nullptr;
EXPECT_EQ(ANeuralNetworksMemoryDesc_create(&mDesc), 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(ANeuralNetworksMemory_createFromDesc(mDesc, &deviceMemory1),
ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksMemory_createFromDesc(mDesc, &deviceMemory2),
ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksMemory_copy(nullptr, deviceMemory1), ANEURALNETWORKS_UNEXPECTED_NULL);
EXPECT_EQ(ANeuralNetworksMemory_copy(deviceMemory1, 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, deviceMemory1), ANEURALNETWORKS_BAD_DATA);
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem2, deviceMemory1), ANEURALNETWORKS_BAD_DATA);
// Device Memory -> Ashmem
// Uninitialized source device memory.
EXPECT_EQ(ANeuralNetworksMemory_copy(deviceMemory1, goodAshmem), ANEURALNETWORKS_BAD_DATA);
// Bad memory size.
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, deviceMemory1), ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksMemory_copy(deviceMemory1, badAshmem1), ANEURALNETWORKS_BAD_DATA);
// Uninitialized source device memory (after a failed copy).
EXPECT_EQ(ANeuralNetworksMemory_copy(badAshmem1, deviceMemory1), ANEURALNETWORKS_BAD_DATA);
EXPECT_EQ(ANeuralNetworksMemory_copy(deviceMemory1, goodAshmem), ANEURALNETWORKS_BAD_DATA);
// Bad memory size.
EXPECT_EQ(ANeuralNetworksMemory_copy(goodAshmem, deviceMemory1), ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksMemory_copy(deviceMemory1, badAshmem2), ANEURALNETWORKS_BAD_DATA);
// Device Memory -> Device Memory
// Uninitialized source device memory.
EXPECT_EQ(ANeuralNetworksMemory_copy(deviceMemory2, deviceMemory1), ANEURALNETWORKS_BAD_DATA);
// TODO: Additionally validate the following:
// - Device memories with incompatible dimensions
// - Deinitialized device memory
ANeuralNetworksMemory_free(deviceMemory1);
ANeuralNetworksMemory_free(deviceMemory2);
}
#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);
}
}
#endif
} // namespace