blob: 5a5e70ff89ec7f45aa47b47f1d260bb562a28221 [file] [log] [blame]
/*
* 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 "NeuralNetworks.h"
#include "NeuralNetworksOEM.h"
#include <android/sharedmem.h>
#include <gtest/gtest.h>
#include <sys/mman.h>
#include <string>
// This file tests all the validations done by the Neural Networks API.
namespace {
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();
}
void createModel() {
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);
ASSERT_EQ(ANeuralNetworksModel_identifyInputsAndOutputs(mModel, 3, inList, 1, outList),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksModel_finish(mModel), ANEURALNETWORKS_NO_ERROR);
mNumOperations = 1;
}
uint32_t mNumOperations = 0;
ANeuralNetworksModel* mModel = nullptr;
};
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;
};
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);
uint32_t dim = 2;
ANeuralNetworksOperandType invalidScalarType{
.type = ANEURALNETWORKS_INT32,
// scalar types can only 0 dimensions.
.dimensionCount = 1,
.dimensions = &dim,
};
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &invalidScalarType),
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) {
uint32_t dim = 2;
ANeuralNetworksOperandType quant8SymmPerChannel{
.type = ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL,
.dimensionCount = 1,
.dimensions = &dim,
.scale = 0.0f,
.zeroPoint = 0,
};
EXPECT_EQ(ANeuralNetworksModel_addOperand(mModel, &quant8SymmPerChannel),
ANEURALNETWORKS_NO_ERROR);
float scale = 1.0f;
ANeuralNetworksSymmPerChannelQuantParams channelQuant{
.channelDim = 0,
.scaleCount = 1,
.scales = &scale,
};
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(nullptr, 0, &channelQuant),
ANEURALNETWORKS_UNEXPECTED_NULL);
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, 0, nullptr),
ANEURALNETWORKS_UNEXPECTED_NULL);
EXPECT_EQ(ANeuralNetworksModel_setOperandSymmPerChannelQuantParams(mModel, 100, &channelQuant),
ANEURALNETWORKS_BAD_DATA);
}
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);
}
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_UNMAPPABLE);
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, 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, 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, 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);
}
// Also see TEST_F(ValidationTestCompilationForDevices, 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, 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);
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);
}
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);
}
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);
}
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);
}
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);
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);
}
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);
AHardwareBuffer_release(buffer);
}
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(ValidationTestExecution, GetOutputOperandRankAndDimensions) {
ANeuralNetworksExecution* execution;
EXPECT_EQ(ANeuralNetworksExecution_create(mCompilation, &execution), ANEURALNETWORKS_NO_ERROR);
float input0 = 1.0f, input1 = 2.0f, output0;
int32_t input2 = 0;
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &input0, sizeof(float)),
ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &input1, sizeof(float)),
ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &input2, sizeof(int32_t)),
ANEURALNETWORKS_NO_ERROR);
EXPECT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &output0, sizeof(float)),
ANEURALNETWORKS_NO_ERROR);
uint32_t rank, dims[4], expectedRank = 1, expectedDims = 1;
// 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(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, 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);
}
class ValidationTestCompilationForDevices : 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, 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, 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, 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, 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);
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);
}
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;
}
}
}
virtual void TearDown() {
ANeuralNetworksCompilation_free(mInvalidCompilation);
ValidationTestModel::TearDown();
}
ANeuralNetworksCompilation* mInvalidCompilation = nullptr;
};
TEST_F(ValidationTestInvalidCompilation, CreateExecutionWithInvalidCompilation) {
if (!mInvalidCompilation) {
return;
}
ASSERT_EQ(ANeuralNetworksCompilation_finish(mInvalidCompilation), ANEURALNETWORKS_BAD_DATA);
ANeuralNetworksExecution* execution = nullptr;
EXPECT_EQ(ANeuralNetworksExecution_create(mInvalidCompilation, &execution),
ANEURALNETWORKS_BAD_STATE);
}
TEST_F(ValidationTestCompilationForDevices, ExecutionTiming) {
ASSERT_EQ(ANeuralNetworksCompilation_finish(mCompilation), ANEURALNETWORKS_NO_ERROR);
// Assume there's a single device.
// TODO:
// - Validate that we fail if there are multiple devices.
// - Validate that we fail if we have Compilation rather than CompilationForDevices.
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);
// TODO:
// - Validate that we cannot setMeasureTiming if the execution has started
// - Validate that we cannot getDuration until the execution has finished
float in0 = 0.0f, in1 = 1.0f, out0 = 0.0f;
int in2 = 0;
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 0, nullptr, &in0, sizeof(in0)),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 1, nullptr, &in1, sizeof(in1)),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksExecution_setInput(execution, 2, nullptr, &in2, sizeof(in2)),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksExecution_setOutput(execution, 0, nullptr, &out0, sizeof(out0)),
ANEURALNETWORKS_NO_ERROR);
ASSERT_EQ(ANeuralNetworksExecution_compute(execution), ANEURALNETWORKS_NO_ERROR);
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) {
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};
std::vector<bool> nullDurations = {false, true};
for (auto e : executions) {
for (auto d : durationCodes) {
for (auto n : nullDurations) {
testDuration(e, d, n);
}
}
}
}
} // namespace