mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 16:09:42 +00:00
Add control flow support to NNAPI VTS tests
See change I98a3edd1. Bug: 148077633 Bug: 148601177 Bug: 136735929 Test: VtsHalNeuralnetworksV1_0TargetTest Test: VtsHalNeuralnetworksV1_1TargetTest Test: VtsHalNeuralnetworksV1_2TargetTest Test: VtsHalNeuralnetworksV1_3TargetTest Change-Id: I1e436cdba404b68026a45797ac4fb3a34f8be76a
This commit is contained in:
@@ -42,10 +42,11 @@ using implementation::PreparedModelCallback;
|
||||
|
||||
Model createModel(const TestModel& testModel) {
|
||||
// Model operands.
|
||||
hidl_vec<Operand> operands(testModel.operands.size());
|
||||
CHECK_EQ(testModel.referenced.size(), 0u); // Not supported in 1.0.
|
||||
hidl_vec<Operand> operands(testModel.main.operands.size());
|
||||
size_t constCopySize = 0, constRefSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
|
||||
DataLocation loc = {};
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
@@ -70,9 +71,9 @@ Model createModel(const TestModel& testModel) {
|
||||
}
|
||||
|
||||
// Model operations.
|
||||
hidl_vec<Operation> operations(testModel.operations.size());
|
||||
std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
|
||||
[](const TestOperation& op) -> Operation {
|
||||
hidl_vec<Operation> operations(testModel.main.operations.size());
|
||||
std::transform(testModel.main.operations.begin(), testModel.main.operations.end(),
|
||||
operations.begin(), [](const TestOperation& op) -> Operation {
|
||||
return {.type = static_cast<OperationType>(op.type),
|
||||
.inputs = op.inputs,
|
||||
.outputs = op.outputs};
|
||||
@@ -80,8 +81,8 @@ Model createModel(const TestModel& testModel) {
|
||||
|
||||
// Constant copies.
|
||||
hidl_vec<uint8_t> operandValues(constCopySize);
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
@@ -102,8 +103,8 @@ Model createModel(const TestModel& testModel) {
|
||||
reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
|
||||
CHECK(mappedPtr != nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
@@ -114,8 +115,8 @@ Model createModel(const TestModel& testModel) {
|
||||
|
||||
return {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = testModel.inputIndexes,
|
||||
.outputIndexes = testModel.outputIndexes,
|
||||
.inputIndexes = testModel.main.inputIndexes,
|
||||
.outputIndexes = testModel.main.outputIndexes,
|
||||
.operandValues = std::move(operandValues),
|
||||
.pools = std::move(pools)};
|
||||
}
|
||||
|
||||
@@ -42,10 +42,10 @@ constexpr uint32_t kOutputPoolIndex = 1;
|
||||
|
||||
Request createRequest(const TestModel& testModel) {
|
||||
// Model inputs.
|
||||
hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
|
||||
hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
|
||||
size_t inputSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
|
||||
const auto& op = testModel.operands[testModel.inputIndexes[i]];
|
||||
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
|
||||
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
|
||||
if (op.data.size() == 0) {
|
||||
// Omitted input.
|
||||
inputs[i] = {.hasNoValue = true};
|
||||
@@ -59,10 +59,10 @@ Request createRequest(const TestModel& testModel) {
|
||||
}
|
||||
|
||||
// Model outputs.
|
||||
hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
|
||||
hidl_vec<RequestArgument> outputs(testModel.main.outputIndexes.size());
|
||||
size_t outputSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
|
||||
const auto& op = testModel.operands[testModel.outputIndexes[i]];
|
||||
for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
|
||||
const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
|
||||
|
||||
// In the case of zero-sized output, we should at least provide a one-byte buffer.
|
||||
// This is because zero-sized tensors are only supported internally to the driver, or
|
||||
@@ -90,8 +90,8 @@ Request createRequest(const TestModel& testModel) {
|
||||
CHECK(inputPtr != nullptr);
|
||||
|
||||
// Copy input data to the memory pool.
|
||||
for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
|
||||
const auto& op = testModel.operands[testModel.inputIndexes[i]];
|
||||
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
|
||||
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
|
||||
if (op.data.size() > 0) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
|
||||
@@ -49,10 +49,11 @@ using V1_0::implementation::PreparedModelCallback;
|
||||
|
||||
Model createModel(const TestModel& testModel) {
|
||||
// Model operands.
|
||||
hidl_vec<Operand> operands(testModel.operands.size());
|
||||
CHECK_EQ(testModel.referenced.size(), 0u); // Not supported in 1.1.
|
||||
hidl_vec<Operand> operands(testModel.main.operands.size());
|
||||
size_t constCopySize = 0, constRefSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
|
||||
DataLocation loc = {};
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
@@ -77,9 +78,9 @@ Model createModel(const TestModel& testModel) {
|
||||
}
|
||||
|
||||
// Model operations.
|
||||
hidl_vec<Operation> operations(testModel.operations.size());
|
||||
std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
|
||||
[](const TestOperation& op) -> Operation {
|
||||
hidl_vec<Operation> operations(testModel.main.operations.size());
|
||||
std::transform(testModel.main.operations.begin(), testModel.main.operations.end(),
|
||||
operations.begin(), [](const TestOperation& op) -> Operation {
|
||||
return {.type = static_cast<OperationType>(op.type),
|
||||
.inputs = op.inputs,
|
||||
.outputs = op.outputs};
|
||||
@@ -87,8 +88,8 @@ Model createModel(const TestModel& testModel) {
|
||||
|
||||
// Constant copies.
|
||||
hidl_vec<uint8_t> operandValues(constCopySize);
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
@@ -109,8 +110,8 @@ Model createModel(const TestModel& testModel) {
|
||||
reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
|
||||
CHECK(mappedPtr != nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
@@ -121,8 +122,8 @@ Model createModel(const TestModel& testModel) {
|
||||
|
||||
return {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = testModel.inputIndexes,
|
||||
.outputIndexes = testModel.outputIndexes,
|
||||
.inputIndexes = testModel.main.inputIndexes,
|
||||
.outputIndexes = testModel.main.outputIndexes,
|
||||
.operandValues = std::move(operandValues),
|
||||
.pools = std::move(pools),
|
||||
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
|
||||
|
||||
@@ -207,10 +207,10 @@ TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) {
|
||||
};
|
||||
|
||||
return {
|
||||
.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = {1},
|
||||
.outputIndexes = {len * 2 + 1},
|
||||
.main = {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = {1},
|
||||
.outputIndexes = {len * 2 + 1}},
|
||||
.isRelaxed = false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,10 +75,11 @@ struct TestConfig {
|
||||
|
||||
Model createModel(const TestModel& testModel) {
|
||||
// Model operands.
|
||||
hidl_vec<Operand> operands(testModel.operands.size());
|
||||
CHECK_EQ(testModel.referenced.size(), 0u); // Not supported in 1.1.
|
||||
hidl_vec<Operand> operands(testModel.main.operands.size());
|
||||
size_t constCopySize = 0, constRefSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
|
||||
DataLocation loc = {};
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
@@ -110,9 +111,9 @@ Model createModel(const TestModel& testModel) {
|
||||
}
|
||||
|
||||
// Model operations.
|
||||
hidl_vec<Operation> operations(testModel.operations.size());
|
||||
std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
|
||||
[](const TestOperation& op) -> Operation {
|
||||
hidl_vec<Operation> operations(testModel.main.operations.size());
|
||||
std::transform(testModel.main.operations.begin(), testModel.main.operations.end(),
|
||||
operations.begin(), [](const TestOperation& op) -> Operation {
|
||||
return {.type = static_cast<OperationType>(op.type),
|
||||
.inputs = op.inputs,
|
||||
.outputs = op.outputs};
|
||||
@@ -120,8 +121,8 @@ Model createModel(const TestModel& testModel) {
|
||||
|
||||
// Constant copies.
|
||||
hidl_vec<uint8_t> operandValues(constCopySize);
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
@@ -142,8 +143,8 @@ Model createModel(const TestModel& testModel) {
|
||||
reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
|
||||
CHECK(mappedPtr != nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
for (uint32_t i = 0; i < testModel.main.operands.size(); i++) {
|
||||
const auto& op = testModel.main.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
@@ -154,15 +155,15 @@ Model createModel(const TestModel& testModel) {
|
||||
|
||||
return {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = testModel.inputIndexes,
|
||||
.outputIndexes = testModel.outputIndexes,
|
||||
.inputIndexes = testModel.main.inputIndexes,
|
||||
.outputIndexes = testModel.main.outputIndexes,
|
||||
.operandValues = std::move(operandValues),
|
||||
.pools = std::move(pools),
|
||||
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
|
||||
}
|
||||
|
||||
static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
|
||||
const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
|
||||
const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size();
|
||||
return byteSize > 1u;
|
||||
}
|
||||
|
||||
@@ -302,17 +303,17 @@ void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestMo
|
||||
// either empty, or have the same number of elements as the number of outputs.
|
||||
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
|
||||
ASSERT_TRUE(outputShapes.size() == 0 ||
|
||||
outputShapes.size() == testModel.outputIndexes.size());
|
||||
outputShapes.size() == testModel.main.outputIndexes.size());
|
||||
break;
|
||||
case OutputType::UNSPECIFIED:
|
||||
// If the model output operands are not fully specified, outputShapes must have
|
||||
// the same number of elements as the number of outputs.
|
||||
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
|
||||
ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
|
||||
ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
|
||||
break;
|
||||
case OutputType::INSUFFICIENT:
|
||||
ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
|
||||
ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
|
||||
ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
|
||||
ASSERT_FALSE(outputShapes[0].isSufficient);
|
||||
return;
|
||||
}
|
||||
@@ -320,7 +321,7 @@ void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestMo
|
||||
// Go through all outputs, check returned output shapes.
|
||||
for (uint32_t i = 0; i < outputShapes.size(); i++) {
|
||||
EXPECT_TRUE(outputShapes[i].isSufficient);
|
||||
const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
|
||||
const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
|
||||
const std::vector<uint32_t> actual = outputShapes[i].dimensions;
|
||||
EXPECT_EQ(expect, actual);
|
||||
}
|
||||
|
||||
@@ -209,10 +209,10 @@ TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) {
|
||||
};
|
||||
|
||||
return {
|
||||
.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = {1},
|
||||
.outputIndexes = {len * 2 + 1},
|
||||
.main = {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = {1},
|
||||
.outputIndexes = {len * 2 + 1}},
|
||||
.isRelaxed = false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -169,7 +169,8 @@ class DeviceMemoryAllocator {
|
||||
if constexpr (ioType == IOType::INPUT) {
|
||||
if (buffer != nullptr) {
|
||||
// TestBuffer -> Shared memory.
|
||||
const auto& testBuffer = kTestModel.operands[kTestModel.inputIndexes[index]].data;
|
||||
const auto& testBuffer =
|
||||
kTestModel.main.operands[kTestModel.main.inputIndexes[index]].data;
|
||||
ASSERT_GT(testBuffer.size(), 0);
|
||||
hidl_memory tmp = nn::allocateSharedMemory(testBuffer.size());
|
||||
sp<IMemory> inputMemory = mapMemory(tmp);
|
||||
@@ -195,26 +196,42 @@ class DeviceMemoryAllocator {
|
||||
const TestModel& kTestModel;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
Subgraph createSubgraph(const TestSubgraph& testSubgraph, uint32_t* constCopySize,
|
||||
std::vector<const TestBuffer*>* constCopies, uint32_t* constRefSize,
|
||||
std::vector<const TestBuffer*>* constReferences) {
|
||||
CHECK(constCopySize != nullptr);
|
||||
CHECK(constCopies != nullptr);
|
||||
CHECK(constRefSize != nullptr);
|
||||
CHECK(constReferences != nullptr);
|
||||
|
||||
Model createModel(const TestModel& testModel) {
|
||||
// Model operands.
|
||||
hidl_vec<Operand> operands(testModel.operands.size());
|
||||
size_t constCopySize = 0, constRefSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
// Operands.
|
||||
hidl_vec<Operand> operands(testSubgraph.operands.size());
|
||||
for (uint32_t i = 0; i < testSubgraph.operands.size(); i++) {
|
||||
const auto& op = testSubgraph.operands[i];
|
||||
|
||||
DataLocation loc = {};
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
loc = {.poolIndex = 0,
|
||||
.offset = static_cast<uint32_t>(constCopySize),
|
||||
.length = static_cast<uint32_t>(op.data.size())};
|
||||
constCopySize += op.data.alignedSize();
|
||||
loc = {
|
||||
.poolIndex = 0,
|
||||
.offset = *constCopySize,
|
||||
.length = static_cast<uint32_t>(op.data.size()),
|
||||
};
|
||||
constCopies->push_back(&op.data);
|
||||
*constCopySize += op.data.alignedSize();
|
||||
} else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
|
||||
loc = {.poolIndex = 0,
|
||||
.offset = static_cast<uint32_t>(constRefSize),
|
||||
.length = static_cast<uint32_t>(op.data.size())};
|
||||
constRefSize += op.data.alignedSize();
|
||||
loc = {
|
||||
.poolIndex = 0,
|
||||
.offset = *constRefSize,
|
||||
.length = static_cast<uint32_t>(op.data.size()),
|
||||
};
|
||||
constReferences->push_back(&op.data);
|
||||
*constRefSize += op.data.alignedSize();
|
||||
} else if (op.lifetime == TestOperandLifeTime::SUBGRAPH) {
|
||||
loc = {
|
||||
.poolIndex = 0,
|
||||
.offset = *op.data.get<uint32_t>(),
|
||||
.length = 0,
|
||||
};
|
||||
}
|
||||
|
||||
V1_2::Operand::ExtraParams extraParams;
|
||||
@@ -233,25 +250,52 @@ Model createModel(const TestModel& testModel) {
|
||||
.extraParams = std::move(extraParams)};
|
||||
}
|
||||
|
||||
// Model operations.
|
||||
hidl_vec<Operation> operations(testModel.operations.size());
|
||||
std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
|
||||
[](const TestOperation& op) -> Operation {
|
||||
// Operations.
|
||||
hidl_vec<Operation> operations(testSubgraph.operations.size());
|
||||
std::transform(testSubgraph.operations.begin(), testSubgraph.operations.end(),
|
||||
operations.begin(), [](const TestOperation& op) -> Operation {
|
||||
return {.type = static_cast<OperationType>(op.type),
|
||||
.inputs = op.inputs,
|
||||
.outputs = op.outputs};
|
||||
});
|
||||
|
||||
return {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = testSubgraph.inputIndexes,
|
||||
.outputIndexes = testSubgraph.outputIndexes};
|
||||
}
|
||||
|
||||
void copyTestBuffers(const std::vector<const TestBuffer*>& buffers, uint8_t* output) {
|
||||
uint32_t offset = 0;
|
||||
for (const TestBuffer* buffer : buffers) {
|
||||
const uint8_t* begin = buffer->get<uint8_t>();
|
||||
const uint8_t* end = begin + buffer->size();
|
||||
std::copy(begin, end, output + offset);
|
||||
offset += buffer->alignedSize();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Model createModel(const TestModel& testModel) {
|
||||
uint32_t constCopySize = 0;
|
||||
uint32_t constRefSize = 0;
|
||||
std::vector<const TestBuffer*> constCopies;
|
||||
std::vector<const TestBuffer*> constReferences;
|
||||
|
||||
Subgraph mainSubgraph = createSubgraph(testModel.main, &constCopySize, &constCopies,
|
||||
&constRefSize, &constReferences);
|
||||
hidl_vec<Subgraph> refSubgraphs(testModel.referenced.size());
|
||||
std::transform(testModel.referenced.begin(), testModel.referenced.end(), refSubgraphs.begin(),
|
||||
[&constCopySize, &constCopies, &constRefSize,
|
||||
&constReferences](const TestSubgraph& testSubgraph) {
|
||||
return createSubgraph(testSubgraph, &constCopySize, &constCopies,
|
||||
&constRefSize, &constReferences);
|
||||
});
|
||||
|
||||
// Constant copies.
|
||||
hidl_vec<uint8_t> operandValues(constCopySize);
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
std::copy(begin, end, operandValues.data() + operands[i].location.offset);
|
||||
}
|
||||
}
|
||||
copyTestBuffers(constCopies, operandValues.data());
|
||||
|
||||
// Shared memory.
|
||||
hidl_vec<hidl_memory> pools = {};
|
||||
@@ -266,27 +310,18 @@ Model createModel(const TestModel& testModel) {
|
||||
reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
|
||||
CHECK(mappedPtr != nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < testModel.operands.size(); i++) {
|
||||
const auto& op = testModel.operands[i];
|
||||
if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
std::copy(begin, end, mappedPtr + operands[i].location.offset);
|
||||
}
|
||||
}
|
||||
copyTestBuffers(constReferences, mappedPtr);
|
||||
}
|
||||
|
||||
return {.main = {.operands = std::move(operands),
|
||||
.operations = std::move(operations),
|
||||
.inputIndexes = testModel.inputIndexes,
|
||||
.outputIndexes = testModel.outputIndexes},
|
||||
return {.main = std::move(mainSubgraph),
|
||||
.referenced = std::move(refSubgraphs),
|
||||
.operandValues = std::move(operandValues),
|
||||
.pools = std::move(pools),
|
||||
.relaxComputationFloat32toFloat16 = testModel.isRelaxed};
|
||||
}
|
||||
|
||||
static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
|
||||
const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
|
||||
const auto byteSize = testModel.main.operands[testModel.main.outputIndexes[index]].data.size();
|
||||
return byteSize > 1u;
|
||||
}
|
||||
|
||||
@@ -320,10 +355,10 @@ static std::pair<Request, std::vector<sp<IBuffer>>> createRequest(
|
||||
std::vector<uint32_t> tokens;
|
||||
|
||||
// Model inputs.
|
||||
hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
|
||||
hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
|
||||
size_t inputSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
|
||||
const auto& op = testModel.operands[testModel.inputIndexes[i]];
|
||||
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
|
||||
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
|
||||
if (op.data.size() == 0) {
|
||||
// Omitted input.
|
||||
inputs[i] = {.hasNoValue = true};
|
||||
@@ -350,10 +385,10 @@ static std::pair<Request, std::vector<sp<IBuffer>>> createRequest(
|
||||
}
|
||||
|
||||
// Model outputs.
|
||||
hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
|
||||
hidl_vec<RequestArgument> outputs(testModel.main.outputIndexes.size());
|
||||
size_t outputSize = 0;
|
||||
for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
|
||||
const auto& op = testModel.operands[testModel.outputIndexes[i]];
|
||||
for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
|
||||
const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
|
||||
if (preferDeviceMemory) {
|
||||
SCOPED_TRACE("Output index = " + std::to_string(i));
|
||||
auto [buffer, token] = allocator.allocate<IOType::OUTPUT>(i);
|
||||
@@ -398,9 +433,9 @@ static std::pair<Request, std::vector<sp<IBuffer>>> createRequest(
|
||||
CHECK(inputMemory.get() != nullptr);
|
||||
uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
|
||||
CHECK(inputPtr != nullptr);
|
||||
for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
|
||||
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
|
||||
if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) {
|
||||
const auto& op = testModel.operands[testModel.inputIndexes[i]];
|
||||
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
|
||||
const uint8_t* begin = op.data.get<uint8_t>();
|
||||
const uint8_t* end = begin + op.data.size();
|
||||
std::copy(begin, end, inputPtr + inputs[i].location.offset);
|
||||
@@ -443,7 +478,7 @@ static std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel, cons
|
||||
if (outputLoc.poolIndex == kOutputPoolIndex) {
|
||||
outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
|
||||
} else {
|
||||
const auto& op = testModel.operands[testModel.outputIndexes[i]];
|
||||
const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
|
||||
if (op.data.size() == 0) {
|
||||
outputBuffers.emplace_back();
|
||||
} else {
|
||||
@@ -638,17 +673,17 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
|
||||
// either empty, or have the same number of elements as the number of outputs.
|
||||
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
|
||||
ASSERT_TRUE(outputShapes.size() == 0 ||
|
||||
outputShapes.size() == testModel.outputIndexes.size());
|
||||
outputShapes.size() == testModel.main.outputIndexes.size());
|
||||
break;
|
||||
case OutputType::UNSPECIFIED:
|
||||
// If the model output operands are not fully specified, outputShapes must have
|
||||
// the same number of elements as the number of outputs.
|
||||
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
|
||||
ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
|
||||
ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
|
||||
break;
|
||||
case OutputType::INSUFFICIENT:
|
||||
ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
|
||||
ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
|
||||
ASSERT_EQ(outputShapes.size(), testModel.main.outputIndexes.size());
|
||||
ASSERT_FALSE(outputShapes[0].isSufficient);
|
||||
return;
|
||||
}
|
||||
@@ -656,7 +691,7 @@ void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>&
|
||||
// Go through all outputs, check returned output shapes.
|
||||
for (uint32_t i = 0; i < outputShapes.size(); i++) {
|
||||
EXPECT_TRUE(outputShapes[i].isSufficient);
|
||||
const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
|
||||
const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
|
||||
const std::vector<uint32_t> actual = outputShapes[i].dimensions;
|
||||
EXPECT_EQ(expect, actual);
|
||||
}
|
||||
@@ -862,7 +897,7 @@ INSTANTIATE_GENERATED_TEST(FencedComputeTest,
|
||||
[](const TestModel& testModel) { return !testModel.expectFailure; });
|
||||
|
||||
INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
|
||||
return testModel.hasQuant8CoupledOperands() && testModel.operations.size() == 1;
|
||||
return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1;
|
||||
});
|
||||
|
||||
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
|
||||
|
||||
@@ -237,12 +237,13 @@ void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel&
|
||||
|
||||
// If the model output operands are fully specified, outputShapes must be either
|
||||
// either empty, or have the same number of elements as the number of outputs.
|
||||
ASSERT_TRUE(outputShapes.size() == 0 || outputShapes.size() == testModel.outputIndexes.size());
|
||||
ASSERT_TRUE(outputShapes.size() == 0 ||
|
||||
outputShapes.size() == testModel.main.outputIndexes.size());
|
||||
|
||||
// Go through all outputs, check returned output shapes.
|
||||
for (uint32_t i = 0; i < outputShapes.size(); i++) {
|
||||
EXPECT_TRUE(outputShapes[i].isSufficient);
|
||||
const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
|
||||
const auto& expect = testModel.main.operands[testModel.main.outputIndexes[i]].dimensions;
|
||||
const std::vector<uint32_t> actual = outputShapes[i].dimensions;
|
||||
EXPECT_EQ(expect, actual);
|
||||
}
|
||||
|
||||
@@ -182,6 +182,7 @@ static float getInvalidScale(OperandType type) {
|
||||
case OperandType::TENSOR_FLOAT16:
|
||||
case OperandType::TENSOR_FLOAT32:
|
||||
case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
|
||||
case OperandType::SUBGRAPH:
|
||||
return 1.0f;
|
||||
case OperandType::TENSOR_INT32:
|
||||
return -1.0f;
|
||||
@@ -220,6 +221,7 @@ static std::vector<int32_t> getInvalidZeroPoints(OperandType type) {
|
||||
case OperandType::TENSOR_FLOAT32:
|
||||
case OperandType::TENSOR_INT32:
|
||||
case OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL:
|
||||
case OperandType::SUBGRAPH:
|
||||
return {1};
|
||||
case OperandType::TENSOR_QUANT8_ASYMM:
|
||||
return {-1, 256};
|
||||
|
||||
Reference in New Issue
Block a user